From ecd49b8c50ed172ab2d3602a0deb22bf077d57cf Mon Sep 17 00:00:00 2001 From: akure Date: Fri, 12 May 2023 17:18:33 +0530 Subject: [PATCH 1/7] adding token factory, authz, and qvesting added multi-sign demo Add vestingcustom module and wire it to app.go Repair import paths Add CreateVestingAccount message for vestingcustom module Fix imports for vestingcustom module Add MsgCreateVestingAccount to vestingcustom/tx.proto file Fix proto types. Improve CLI command to create vesting accounts with start_time. Wire bankKeeper to module keeper.go. Implement logic about creating a vesting account. Implement required external methods to expected_keeper.go. Compiled tx protobuf. Wire app.BankKeeper to VestingCustomKeeper Remove simulation folder and files. Remove unused vars from cli/tx.go. Fix testutil/keeper/vestingcustom.go missing param after bankKeeper implementation. Documentation about custom tx create-vesting-account of x/vestingcustom module Remove unused msg_server_test.go Remove --delayed flag for custom create_vesting_account command and message Remove unused errors.go containing ErrSample Remove unused DefaultIndex variable on genesis.go Rename x/vestingcustom to x/qtransfer as well as everything related Add openapi.yml qvesting endpoints Add attributes to event emitted by x/qvesting create_vesting_account message. Add constants.go for x/qvesting module. Remove unused variables from x/qvesting/client/cli tx.go and tx_create_vesting_account.go Correct README.md with more consistent information about the reason of development as wrapper of core x/auth/vesting module Reorder and remove useless information from README.md about x/qvesting Add quasar_localnet.sh and vesting_schedule_standard.sh for create-vesting-account from regular my_treasury account Remove unused SpendableCoins() method from BankKeeper Remove useless attribute from custom emitted event on create_vesting_account Remove duplicated action:create_vesting_account attribute form custom emitted event Update README.md fixing --chain-id and adding Multisig guidelines to create continuous vesting accounts. Add vesting_schedule_multisig.sh to perform tests automatically. Add Ledger information to README.md and vesting_schedule_ledger.sh for testing. Correct a command on vesting_schedule_multisig.sh. Implement query spendable balances Add Upgrade handler for v0.1.1 for software-upgrade proposal Update arguments passed from Update struct to UpgradeHandler Update upgrade_handler_v0_1_1.sh script to test upgradeHandler Polish shell script and READMEs Add pagination to req on qvesting spendable-balances query cli Fix query spendable-balances on qvesting module with pagination Update readme by adding query CLI command with pagination explanation and usage Remove unused method Validated the StartTime against the blockTime.Unix() to be higher; Removed msg.StartTime <= 0 and msg.EndTime <= 0 validations as redundant and left msg.StartTime > msg.EndTime as it was in order to still validating the EndTime is at least equal to StartTime to allow instant vestings of the full vesting amount; Added to emitted event start_time and end_time. Updated short and added the long description accordingly. Register REST and gRPC routes Implement query vesting accounts Lint correction about handling error returning nothing as function requirement says Add README.md as spec documents for qvesting module Using AddVestingAccount() method from keeper Adding missing imports for qvesting/query.proto Implementing missing query endpoints on swagger doc Implementing missing query definitions on swagger doc Removing extra qvesting path Fix timing of execution after audit changes Fixing byte error retrieving deriving the address during query vesting accounts Remove unused function Removing unused function and fixing multisig and ledger test cases accordingly to new audit changes Fixes endpoints and polish code adding token factory module part 1 added token factory test cases updated some unit tests. and removed reduntant files. note - more unit tests to be added updated testcases Signed-off-by: akure Squash all cli, grpc and msgs in single files for easier read Implement qVesting Locked Supply endpoint to query the locked supply amount in Vesting Accounts for a given denom Move iteration of vesting accounts to unexported keeper method invoking callback function; Polish cli query cmds description; added authz fix missing contents on cherry-pick Reproducible build fix. Updating e2e Readme. --- Dockerfile | 21 +- LOCALNET.md | 1 + Makefile | 3 +- MakefileDebugBin | 344 +++ README.md | 19 +- app/app.go | 149 +- app/keepers/keepers.go | 80 + app/upgrades/types.go | 2 + app/upgrades/v0/constants.go | 21 + app/upgrades/v0/export_test.go | 10 + app/upgrades/v0/upgrades.go | 37 + cmd/quasarnoded/cmd/config.go | 15 + config.yml | 80 - demos/authz-demo/authz_gov_demo.sh | 44 + demos/authz-demo/quasar_localnet.sh | 93 + demos/authz-demo/run_authz_gov_demo.sh | 7 + demos/bandchain-config/README.md | 50 - demos/ica-packet-forward/README.md | 78 - demos/ica-packet-forward/cosmos.yml | 30 - demos/ica-packet-forward/hermes_config.toml | 178 -- demos/ica-packet-forward/osmosis.yml | 35 - demos/ica-packet-forward/quasar.yml | 30 - demos/orion-manual-demo/band_testnet_init.sh | 59 - .../complete_zone_info_map-proposal.json | 59 - demos/orion-manual-demo/demo.md | 34 +- .../orion-manual-demo/deploy_and_test_ica.sh | 43 - demos/orion-manual-demo/forwarding-demo.md | 28 - ...is_denom_to_quasar_denom_map-proposal.json | 16 - ..._denom_to_native_zone_id_map-proposal.json | 16 - ...amm-forwarding-and-request-deposit-demo.md | 92 - .../test-intergamm-token-transfer.md | 116 - .../verify-channel-ids-guide.md | 30 - .../verify-ibc-denoms-guide.md | 55 - demos/osmosis-config/tf_localnet.sh | 83 + demos/tokenfactory/README.md | 106 + demos/tokenfactory/quasar_localnet.sh | 93 + demos/upgrade-handler/README.md | 29 + demos/upgrade-handler/quasar_localnet.sh | 82 + demos/upgrade-handler/v0.1.1/README.md | 28 + .../v0.1.1/upgrade_handler_v0_1_1.sh | 48 + demos/upgrade-handler/v1.0.0/README.md | 35 + .../v1.0.0/restart_v1_0_0_binary.sh | 17 + .../v1.0.0/upgrade_handler_v1.0.0.sh | 72 + demos/vesting-schedule/README.md | 149 ++ demos/vesting-schedule/quasar_localnet.sh | 82 + .../vesting_schedule_ledger.sh | 78 + .../vesting_schedule_multisig.sh | 83 + .../vesting_schedule_standard.sh | 76 + docs/static/openapi.yml | 194 ++ go.mod | 22 +- go.sum | 262 +- proto/qvesting/genesis.proto | 14 + proto/qvesting/params.proto | 12 + proto/qvesting/query.proto | 92 + proto/qvesting/tx.proto | 30 + .../v1beta1/authorityMetadata.proto | 17 + proto/tokenfactory/v1beta1/genesis.proto | 33 + proto/tokenfactory/v1beta1/params.proto | 26 + proto/tokenfactory/v1beta1/query.proto | 71 + proto/tokenfactory/v1beta1/tx.proto | 112 + tests/e2e/README.md | 2 + testutil/keeper/common.go | 40 + testutil/keeper/qvesting.go | 98 + testutil/keeper/tfkeeper.go | 35 + testutil/setup.go | 73 +- x/qvesting/README.md | 46 + x/qvesting/client/cli/query.go | 162 ++ x/qvesting/client/cli/tx.go | 84 + x/qvesting/genesis.go | 24 + x/qvesting/handler.go | 29 + x/qvesting/keeper/grpc_query.go | 138 + x/qvesting/keeper/grpc_query_test.go | 21 + x/qvesting/keeper/keeper.go | 93 + x/qvesting/keeper/msg_server.go | 103 + x/qvesting/keeper/params.go | 16 + x/qvesting/keeper/params_test.go | 18 + x/qvesting/module.go | 182 ++ x/qvesting/types/codec.go | 29 + x/qvesting/types/constants.go | 14 + x/qvesting/types/expected_keepers.go | 24 + x/qvesting/types/genesis.go | 17 + x/qvesting/types/genesis.pb.go | 321 +++ x/qvesting/types/genesis_test.go | 40 + x/qvesting/types/keys.go | 31 + x/qvesting/types/msgs.go | 73 + x/qvesting/types/msgs_test.go | 40 + x/qvesting/types/params.go | 39 + x/qvesting/types/params.pb.go | 264 ++ x/qvesting/types/query.pb.go | 1917 ++++++++++++++ x/qvesting/types/query.pb.gw.go | 456 ++++ x/qvesting/types/tx.pb.go | 760 ++++++ x/qvesting/types/types.go | 1 + x/tokenfactory/README.md | 193 ++ x/tokenfactory/bindings/custom_msg_test.go | 1 + x/tokenfactory/bindings/custom_query_test.go | 76 + x/tokenfactory/bindings/helpers_test.go | 94 + x/tokenfactory/bindings/message_plugin.go | 332 +++ x/tokenfactory/bindings/queries.go | 61 + x/tokenfactory/bindings/query_plugin.go | 122 + .../bindings/testdata/download_releases.sh | 19 + .../bindings/testdata/token_reflect.wasm | Bin 0 -> 2194768 bytes x/tokenfactory/bindings/testdata/version.txt | 1 + x/tokenfactory/bindings/types/msg.go | 59 + x/tokenfactory/bindings/types/query.go | 61 + x/tokenfactory/bindings/types/types.go | 37 + x/tokenfactory/bindings/validate_msg_test.go | 416 +++ .../bindings/validate_queries_test.go | 117 + x/tokenfactory/bindings/wasm.go | 29 + x/tokenfactory/client/cli/query.go | 122 + x/tokenfactory/client/cli/tx.go | 231 ++ x/tokenfactory/keeper/admins.go | 49 + x/tokenfactory/keeper/bankactions.go | 52 + x/tokenfactory/keeper/createdenom.go | 93 + x/tokenfactory/keeper/createdenom_test.go | 48 + x/tokenfactory/keeper/creators.go | 27 + x/tokenfactory/keeper/genesis.go | 58 + x/tokenfactory/keeper/genesis_test.go | 62 + x/tokenfactory/keeper/grpc_query.go | 35 + x/tokenfactory/keeper/keeper.go | 81 + x/tokenfactory/keeper/msg_server.go | 178 ++ x/tokenfactory/keeper/params.go | 18 + x/tokenfactory/keeper/params_test.go | 19 + x/tokenfactory/module.go | 205 ++ x/tokenfactory/simulation/sim_msgs.go | 134 + x/tokenfactory/testhelpers/consts.go | 8 + x/tokenfactory/testhelpers/suite.go | 66 + x/tokenfactory/types/authorityMetadata.go | 15 + x/tokenfactory/types/authorityMetadata.pb.go | 352 +++ x/tokenfactory/types/authzcodec/codec.go | 24 + x/tokenfactory/types/codec.go | 47 + x/tokenfactory/types/denoms.go | 84 + x/tokenfactory/types/denoms_test.go | 130 + x/tokenfactory/types/errors.go | 23 + x/tokenfactory/types/events.go | 17 + x/tokenfactory/types/expected_keepers.go | 33 + x/tokenfactory/types/genesis.go | 51 + x/tokenfactory/types/genesis.pb.go | 649 +++++ x/tokenfactory/types/genesis_test.go | 141 + x/tokenfactory/types/keys.go | 49 + x/tokenfactory/types/msgs.go | 216 ++ x/tokenfactory/types/msgs_test.go | 451 ++++ x/tokenfactory/types/params.go | 79 + x/tokenfactory/types/params.pb.go | 381 +++ x/tokenfactory/types/query.pb.go | 1331 ++++++++++ x/tokenfactory/types/query.pb.gw.go | 355 +++ x/tokenfactory/types/tx.pb.go | 2342 +++++++++++++++++ 146 files changed, 17681 insertions(+), 1204 deletions(-) create mode 100644 MakefileDebugBin create mode 100644 app/keepers/keepers.go create mode 100644 app/upgrades/v0/constants.go create mode 100644 app/upgrades/v0/export_test.go create mode 100644 app/upgrades/v0/upgrades.go delete mode 100644 config.yml create mode 100755 demos/authz-demo/authz_gov_demo.sh create mode 100755 demos/authz-demo/quasar_localnet.sh create mode 100755 demos/authz-demo/run_authz_gov_demo.sh delete mode 100644 demos/bandchain-config/README.md delete mode 100644 demos/ica-packet-forward/README.md delete mode 100644 demos/ica-packet-forward/cosmos.yml delete mode 100644 demos/ica-packet-forward/hermes_config.toml delete mode 100644 demos/ica-packet-forward/osmosis.yml delete mode 100644 demos/ica-packet-forward/quasar.yml delete mode 100755 demos/orion-manual-demo/band_testnet_init.sh delete mode 100644 demos/orion-manual-demo/complete_zone_info_map-proposal.json delete mode 100755 demos/orion-manual-demo/deploy_and_test_ica.sh delete mode 100644 demos/orion-manual-demo/forwarding-demo.md delete mode 100644 demos/orion-manual-demo/osmosis_denom_to_quasar_denom_map-proposal.json delete mode 100644 demos/orion-manual-demo/quasar_denom_to_native_zone_id_map-proposal.json delete mode 100644 demos/orion-manual-demo/test-intergamm-forwarding-and-request-deposit-demo.md delete mode 100644 demos/orion-manual-demo/test-intergamm-token-transfer.md delete mode 100644 demos/orion-manual-demo/verify-channel-ids-guide.md delete mode 100644 demos/orion-manual-demo/verify-ibc-denoms-guide.md create mode 100755 demos/osmosis-config/tf_localnet.sh create mode 100644 demos/tokenfactory/README.md create mode 100755 demos/tokenfactory/quasar_localnet.sh create mode 100644 demos/upgrade-handler/README.md create mode 100755 demos/upgrade-handler/quasar_localnet.sh create mode 100644 demos/upgrade-handler/v0.1.1/README.md create mode 100755 demos/upgrade-handler/v0.1.1/upgrade_handler_v0_1_1.sh create mode 100644 demos/upgrade-handler/v1.0.0/README.md create mode 100755 demos/upgrade-handler/v1.0.0/restart_v1_0_0_binary.sh create mode 100755 demos/upgrade-handler/v1.0.0/upgrade_handler_v1.0.0.sh create mode 100644 demos/vesting-schedule/README.md create mode 100755 demos/vesting-schedule/quasar_localnet.sh create mode 100755 demos/vesting-schedule/vesting_schedule_ledger.sh create mode 100755 demos/vesting-schedule/vesting_schedule_multisig.sh create mode 100755 demos/vesting-schedule/vesting_schedule_standard.sh create mode 100644 proto/qvesting/genesis.proto create mode 100644 proto/qvesting/params.proto create mode 100644 proto/qvesting/query.proto create mode 100644 proto/qvesting/tx.proto create mode 100644 proto/tokenfactory/v1beta1/authorityMetadata.proto create mode 100644 proto/tokenfactory/v1beta1/genesis.proto create mode 100644 proto/tokenfactory/v1beta1/params.proto create mode 100644 proto/tokenfactory/v1beta1/query.proto create mode 100644 proto/tokenfactory/v1beta1/tx.proto create mode 100644 testutil/keeper/qvesting.go create mode 100644 testutil/keeper/tfkeeper.go create mode 100644 x/qvesting/README.md create mode 100644 x/qvesting/client/cli/query.go create mode 100644 x/qvesting/client/cli/tx.go create mode 100644 x/qvesting/genesis.go create mode 100644 x/qvesting/handler.go create mode 100644 x/qvesting/keeper/grpc_query.go create mode 100644 x/qvesting/keeper/grpc_query_test.go create mode 100644 x/qvesting/keeper/keeper.go create mode 100644 x/qvesting/keeper/msg_server.go create mode 100644 x/qvesting/keeper/params.go create mode 100644 x/qvesting/keeper/params_test.go create mode 100644 x/qvesting/module.go create mode 100644 x/qvesting/types/codec.go create mode 100644 x/qvesting/types/constants.go create mode 100644 x/qvesting/types/expected_keepers.go create mode 100644 x/qvesting/types/genesis.go create mode 100644 x/qvesting/types/genesis.pb.go create mode 100644 x/qvesting/types/genesis_test.go create mode 100644 x/qvesting/types/keys.go create mode 100644 x/qvesting/types/msgs.go create mode 100644 x/qvesting/types/msgs_test.go create mode 100644 x/qvesting/types/params.go create mode 100644 x/qvesting/types/params.pb.go create mode 100644 x/qvesting/types/query.pb.go create mode 100644 x/qvesting/types/query.pb.gw.go create mode 100644 x/qvesting/types/tx.pb.go create mode 100644 x/qvesting/types/types.go create mode 100644 x/tokenfactory/README.md create mode 100644 x/tokenfactory/bindings/custom_msg_test.go create mode 100644 x/tokenfactory/bindings/custom_query_test.go create mode 100644 x/tokenfactory/bindings/helpers_test.go create mode 100644 x/tokenfactory/bindings/message_plugin.go create mode 100644 x/tokenfactory/bindings/queries.go create mode 100644 x/tokenfactory/bindings/query_plugin.go create mode 100755 x/tokenfactory/bindings/testdata/download_releases.sh create mode 100755 x/tokenfactory/bindings/testdata/token_reflect.wasm create mode 100644 x/tokenfactory/bindings/testdata/version.txt create mode 100644 x/tokenfactory/bindings/types/msg.go create mode 100644 x/tokenfactory/bindings/types/query.go create mode 100644 x/tokenfactory/bindings/types/types.go create mode 100644 x/tokenfactory/bindings/validate_msg_test.go create mode 100644 x/tokenfactory/bindings/validate_queries_test.go create mode 100644 x/tokenfactory/bindings/wasm.go create mode 100644 x/tokenfactory/client/cli/query.go create mode 100644 x/tokenfactory/client/cli/tx.go create mode 100644 x/tokenfactory/keeper/admins.go create mode 100644 x/tokenfactory/keeper/bankactions.go create mode 100644 x/tokenfactory/keeper/createdenom.go create mode 100644 x/tokenfactory/keeper/createdenom_test.go create mode 100644 x/tokenfactory/keeper/creators.go create mode 100644 x/tokenfactory/keeper/genesis.go create mode 100644 x/tokenfactory/keeper/genesis_test.go create mode 100644 x/tokenfactory/keeper/grpc_query.go create mode 100644 x/tokenfactory/keeper/keeper.go create mode 100644 x/tokenfactory/keeper/msg_server.go create mode 100644 x/tokenfactory/keeper/params.go create mode 100644 x/tokenfactory/keeper/params_test.go create mode 100644 x/tokenfactory/module.go create mode 100644 x/tokenfactory/simulation/sim_msgs.go create mode 100644 x/tokenfactory/testhelpers/consts.go create mode 100644 x/tokenfactory/testhelpers/suite.go create mode 100644 x/tokenfactory/types/authorityMetadata.go create mode 100644 x/tokenfactory/types/authorityMetadata.pb.go create mode 100644 x/tokenfactory/types/authzcodec/codec.go create mode 100644 x/tokenfactory/types/codec.go create mode 100644 x/tokenfactory/types/denoms.go create mode 100644 x/tokenfactory/types/denoms_test.go create mode 100644 x/tokenfactory/types/errors.go create mode 100644 x/tokenfactory/types/events.go create mode 100644 x/tokenfactory/types/expected_keepers.go create mode 100644 x/tokenfactory/types/genesis.go create mode 100644 x/tokenfactory/types/genesis.pb.go create mode 100644 x/tokenfactory/types/genesis_test.go create mode 100644 x/tokenfactory/types/keys.go create mode 100644 x/tokenfactory/types/msgs.go create mode 100644 x/tokenfactory/types/msgs_test.go create mode 100644 x/tokenfactory/types/params.go create mode 100644 x/tokenfactory/types/params.pb.go create mode 100644 x/tokenfactory/types/query.pb.go create mode 100644 x/tokenfactory/types/query.pb.gw.go create mode 100644 x/tokenfactory/types/tx.pb.go diff --git a/Dockerfile b/Dockerfile index 3d26ba5b1..9f74f5400 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 -ARG GO_VERSION="1.18" -ARG RUNNER_IMAGE="gcr.io/distroless/static" +ARG GO_VERSION="1.20" +ARG RUNNER_IMAGE="gcr.io/distroless/static-debian11" # -------------------------------------------------------- # Builder @@ -25,12 +25,12 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ go mod download # Cosmwasm - Download correct libwasmvm version -RUN WASMVM_VERSION=$(go list -m github.com/CosmWasm/wasmvm | cut -d ' ' -f 2) && \ - wget https://github.com/CosmWasm/wasmvm/releases/download/$WASMVM_VERSION/libwasmvm_muslc.$(uname -m).a \ - -O /lib/libwasmvm_muslc.a && \ +RUN ARCH=$(uname -m) && WASMVM_VERSION=$(go list -m github.com/CosmWasm/wasmvm | sed 's/.* //') && \ + wget https://github.com/CosmWasm/wasmvm/releases/download/$WASMVM_VERSION/libwasmvm_muslc.$ARCH.a \ + -O /lib/libwasmvm_muslc.a && \ # verify checksum wget https://github.com/CosmWasm/wasmvm/releases/download/$WASMVM_VERSION/checksums.txt -O /tmp/checksums.txt && \ - sha256sum /lib/libwasmvm_muslc.a | grep $(cat /tmp/checksums.txt | grep $(uname -m) | cut -d ' ' -f 1) + sha256sum /lib/libwasmvm_muslc.a | grep $(cat /tmp/checksums.txt | grep libwasmvm_muslc.$ARCH | cut -d ' ' -f 1) # Copy the remaining files COPY . . @@ -52,18 +52,15 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ -X github.com/cosmos/cosmos-sdk/version.BuildTags='netgo,ledger,muslc' \ -w -s -linkmode=external -extldflags '-Wl,-z,muldefs -static'" \ -trimpath \ - -o build/quasarnoded ./cmd/quasarnoded + -o build/quasarnoded \ + /quasar/cmd/quasarnoded/main.go # -------------------------------------------------------- # Runner # -------------------------------------------------------- -FROM alpine:3.17.2 as runner - -ENV PACKAGES bash - -RUN apk add --no-cache $PACKAGES +FROM ${RUNNER_IMAGE} as runner COPY --from=builder /quasar/build/quasarnoded /bin/quasarnoded diff --git a/LOCALNET.md b/LOCALNET.md index 4d797a3bd..ff6358b89 100644 --- a/LOCALNET.md +++ b/LOCALNET.md @@ -1,5 +1,6 @@ # Quasar Local Testnet (localnet) +## NOTE - This feature is as of now deprecated. We will be bringing better localnet support in future. To run a small network of Quasar nodes locally, first generate their respective configuration: diff --git a/Makefile b/Makefile index f76e1ae96..7e0e46fad 100644 --- a/Makefile +++ b/Makefile @@ -203,7 +203,7 @@ $(MOCKSDIR)/: ### Tests & Simulation ### ############################################################################### -PACKAGES_UNIT=$(shell go list ./x/epochs/... ./x/qoracle/... | grep -E -v "simapp|e2e" | grep -E -v "x/qoracle/client/cli") +PACKAGES_UNIT=$(shell go list ./x/epochs/... ./x/qoracle/... ./x/tokenfactory/... | grep -E -v "simapp|e2e" | grep -E -v "x/qoracle/client/cli") PACKAGES_E2E=$(shell go list ./... | grep '/tests/e2e') PACKAGES_SIM=$(shell go list ./... | grep '/tests/simulator') TEST_PACKAGES=./... @@ -342,6 +342,7 @@ docker-e2e-build: DOCKER_BUILDKIT=1 docker build \ -t $$chain:local \ -t $$chain:local-distroless \ + --build-arg GO_VERSION=$(GO_VERSION) \ --build-arg RUNNER_IMAGE=$(RUNNER_BASE_IMAGE_DISTROLESS) \ --build-arg GIT_VERSION=$(VERSION) \ --build-arg GIT_COMMIT=$(COMMIT) \ diff --git a/MakefileDebugBin b/MakefileDebugBin new file mode 100644 index 000000000..5b6482a29 --- /dev/null +++ b/MakefileDebugBin @@ -0,0 +1,344 @@ +#!/usr/bin/make -f + +VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//') +COMMIT := $(shell git log -1 --format='%H') +LEDGER_ENABLED ?= true +SDK_PACK := $(shell go list -m github.com/cosmos/cosmos-sdk | sed 's/ /\@/g') +GO_VERSION := $(shell cat go.mod | grep -E 'go [0-9].[0-9]+' | cut -d ' ' -f 2) +DOCKER := $(shell which docker) +GOMOD := $(shell go list -m) +BUILDDIR ?= $(CURDIR)/build +MOCKSDIR = $(CURDIR)/testutil/mock + +export GO111MODULE = on + +## Helper function to show help with `make` or `make help` + +.DEFAULT_GOAL := help + +HELP_FUN = \ + %help; while(<>){push@{$$help{$$2//'targets'}},[$$1,$$3] \ + if/^([\w-_]+)\s*:.*\#\#(?:@(\w+))?\s(.*)$$/}; \ + print"$$_:\n", map" $$_->[0]".(" "x(40-length($$_->[0])))."$$_->[1]\n",\ + @{$$help{$$_}},"\n" for keys %help; \ + +help: ##@misc Show this help + @echo "Usage: make [target] ...\n" + @perl -e '$(HELP_FUN)' $(MAKEFILE_LIST) + + + +# process build tags + +build_tags = netgo +ifeq ($(LEDGER_ENABLED),true) + ifeq ($(OS),Windows_NT) + GCCEXE = $(shell where gcc.exe 2> NUL) + ifeq ($(GCCEXE),) + $(error gcc.exe not installed for ledger support, please install or set LEDGER_ENABLED=false) + else + build_tags += ledger + endif + else + UNAME_S = $(shell uname -s) + ifeq ($(UNAME_S),OpenBSD) + $(warning OpenBSD detected, disabling ledger support (https://github.com/cosmos/cosmos-sdk/issues/1988)) + else + GCC = $(shell command -v gcc 2> /dev/null) + ifeq ($(GCC),) + $(error gcc not installed for ledger support, please install or set LEDGER_ENABLED=false) + else + build_tags += ledger + endif + endif + endif +endif + +ifeq (cleveldb,$(findstring cleveldb,$(QUASAR_BUILD_OPTIONS))) + build_tags += gcc +else ifeq (rocksdb,$(findstring rocksdb,$(QUASAR_BUILD_OPTIONS))) + build_tags += gcc +endif +build_tags += $(BUILD_TAGS) +build_tags_debug += $(BUILD_TAGS) +build_tags := $(strip $(build_tags)) + +whitespace := +whitespace += $(whitespace) +comma := , +build_tags_comma_sep := $(subst $(whitespace),$(comma),$(build_tags)) + +# process linker flags + +ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=quasar \ + -X github.com/cosmos/cosmos-sdk/version.AppName=quasarnoded \ + -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \ + -X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \ + -X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)" + +ifeq (cleveldb,$(findstring cleveldb,$(QUASAR_BUILD_OPTIONS))) + ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=cleveldb +else ifeq (rocksdb,$(findstring rocksdb,$(QUASAR_BUILD_OPTIONS))) + ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=rocksdb +endif + +ldflags-debug := $(ldflags) + +ifeq (,$(findstring nostrip,$(QUASAR_BUILD_OPTIONS))) + ldflags += -w -s +endif + +ifeq ($(LINK_STATICALLY),true) + ldflags += -linkmode=external -extldflags "-Wl,-z,muldefs -static" + ldflags-debug += -linkmode=external -extldflags "-Wl,-z,muldefs -static" +endif + +ldflags += $(LDFLAGS) +ldflags-debug += $(LDFLAGS) + +ldflags := $(strip $(ldflags)) + +BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)' +BUILD_FLAGS_DEBUG := -tags "$(build_tags_debug)" -ldflags '$(ldflags-debug)' +# check for nostrip option +ifeq (,$(findstring nostrip,$(QUASAR_BUILD_OPTIONS))) + BUILD_FLAGS += -trimpath +endif + +############################################################################### +### Build ### +############################################################################### + +all: install lint test + +#BUILD_TARGETS := build install +BUILD_TARGETS_DEBUG := build install +build: BUILD_ARGS=-o $(BUILDDIR)/ + +$(BUILD_TARGETS): go.sum $(BUILDDIR)/ + go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) ./cmd/quasarnoded + +$(BUILD_TARGETS_DEBUG): go.sum $(BUILDDIR)/ + go $@ -mod=readonly $(BUILD_FLAGS_DEBUG) -gcflags='all=-N -l' $(BUILD_ARGS) ./cmd/quasarnoded + +$(BUILDDIR)/: + mkdir -p $(BUILDDIR)/ + +# Cross-building for arm64 from amd64 (or viceversa) takes +# a lot of time due to QEMU virtualization but it's the only way (afaik) +# to get a statically linked binary with CosmWasm + +build-reproducible: build-reproducible-amd64 build-reproducible-arm64 + +build-reproducible-amd64: $(BUILDDIR)/ + $(DOCKER) buildx create --name quasarbuilder || true + $(DOCKER) buildx use quasarbuilder + $(DOCKER) buildx build \ + --build-arg GO_VERSION=$(GO_VERSION) \ + --build-arg RUNNER_IMAGE=$(RUNNER_BASE_IMAGE_DISTROLESS) \ + --build-arg GIT_VERSION=$(VERSION) \ + --build-arg GIT_COMMIT=$(COMMIT) \ + --platform linux/amd64 \ + -t quasar-amd64 \ + --load \ + -f Dockerfile . + $(DOCKER) rm -f quasarbinary || true + $(DOCKER) create -ti --name quasarbinary quasar-amd64 + $(DOCKER) cp quasarbinary:/bin/quasarnoded $(BUILDDIR)/quasarnoded-linux-amd64 + $(DOCKER) rm -f quasarbinary + +build-reproducible-arm64: $(BUILDDIR)/ + $(DOCKER) buildx create --name quasarbuilder || true + $(DOCKER) buildx use quasarbuilder + $(DOCKER) buildx build \ + --build-arg GO_VERSION=$(GO_VERSION) \ + --build-arg RUNNER_IMAGE=$(RUNNER_BASE_IMAGE_DISTROLESS) \ + --build-arg GIT_VERSION=$(VERSION) \ + --build-arg GIT_COMMIT=$(COMMIT) \ + --platform linux/arm64 \ + -t quasar-arm64 \ + --load \ + -f Dockerfile . + $(DOCKER) rm -f quasarbinary || true + $(DOCKER) create -ti --name quasarbinary quasar-arm64 + $(DOCKER) cp quasarbinary:/bin/quasarnoded $(BUILDDIR)/quasarnoded-linux-arm64 + $(DOCKER) rm -f quasarbinary + +build-linux: go.sum + LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build + +go.sum: go.mod + @echo "--> Ensure dependencies have not been modified" + @go mod verify + +############################################################################### +### Proto & Mock Generation ### +############################################################################### + +proto-all: proto-format proto-gen + +proto-gen: + @echo "Generating Protobuf files" + @sh ./scripts/protocgen.sh + +proto-doc: + @echo "Generating Protoc docs" + @sh ./scripts/generate-docs.sh + +.PHONY: proto-gen proto-doc + +mocks: $(MOCKSDIR)/ + mockgen -package=mock -destination=$(MOCKSDIR)/ibc_channel_mocks.go $(GOMOD)/x/qoracle/types ChannelKeeper +# mockgen -package=mock -destination=$(MOCKSDIR)/ica_mocks.go $(GOMOD)/x/intergamm/types ICAControllerKeeper +# mockgen -package=mock -destination=$(MOCKSDIR)/ibc_mocks.go $(GOMOD)/x/intergamm/types IBCTransferKeeper + mockgen -package=mock -destination=$(MOCKSDIR)/ics4_wrapper_mocks.go $(GOMOD)/x/qoracle/types ICS4Wrapper + mockgen -package=mock -destination=$(MOCKSDIR)/ibc_port_mocks.go $(GOMOD)/x/qoracle/types PortKeeper +# mockgen -package=mock -destination=$(MOCKSDIR)/ibc_connection_mocks.go $(GOMOD)/x/intergamm/types ConnectionKeeper +# mockgen -package=mock -destination=$(MOCKSDIR)/ibc_client_mocks.go $(GOMOD)/x/intergamm/types ClientKeeper + +$(MOCKSDIR)/: + mkdir -p $(MOCKSDIR)/ + +############################################################################### +### Tests & Simulation ### +############################################################################### + +PACKAGES_UNIT=$(shell go list ./x/epochs/... ./x/qoracle/... | grep -E -v "simapp|e2e" | grep -E -v "x/qoracle/client/cli") +PACKAGES_E2E=$(shell go list ./... | grep '/tests/e2e') +PACKAGES_SIM=$(shell go list ./... | grep '/tests/simulator') +TEST_PACKAGES=./... + +include tests/e2e/Makefile + +test: test-unit test-build + +test-all: check test-race test-cover + +test-unit: + @VERSION=$(VERSION) go test -mod=readonly -tags='ledger test_ledger_mock norace' $(PACKAGES_UNIT) + +test-race: + @VERSION=$(VERSION) go test -mod=readonly -race -tags='ledger test_ledger_mock' $(PACKAGES_UNIT) + +test-cover: + @VERSION=$(VERSION) go test -mod=readonly -timeout 30m -coverprofile=coverage.txt -tags='norace' -covermode=atomic $(PACKAGES_UNIT) + +test-sim-suite: + @VERSION=$(VERSION) go test -mod=readonly $(PACKAGES_SIM) + +test-sim-app: + @VERSION=$(VERSION) go test -mod=readonly -run ^TestFullAppSimulation -v $(PACKAGES_SIM) + +test-sim-determinism: + @VERSION=$(VERSION) go test -mod=readonly -run ^TestAppStateDeterminism -v $(PACKAGES_SIM) + +test-sim-bench: + @VERSION=$(VERSION) go test -benchmem -run ^BenchmarkFullAppSimulation -bench ^BenchmarkFullAppSimulation -cpuprofile cpu.out $(PACKAGES_SIM) + +benchmark: + @go test -mod=readonly -bench=. $(PACKAGES_UNIT) + +############################################################################### +### Smart Contracts ### +############################################################################### + +compile-wasm-artifacts: + cd smart-contracts && \ + ./compile_contracts.sh + + +############################################################################### +### Docker ### +############################################################################### + +RUNNER_BASE_IMAGE_DISTROLESS := gcr.io/distroless/static +RUNNER_BASE_IMAGE_ALPINE := alpine:3.16 +RUNNER_BASE_IMAGE_NONROOT := gcr.io/distroless/static:nonroot + +docker-build: + @DOCKER_BUILDKIT=1 docker build \ + -t quasar:local \ + -t quasar:local-distroless \ + --build-arg GO_VERSION=$(GO_VERSION) \ + --build-arg RUNNER_IMAGE=$(RUNNER_BASE_IMAGE_DISTROLESS) \ + --build-arg GIT_VERSION=$(VERSION) \ + --build-arg GIT_COMMIT=$(COMMIT) \ + -f Dockerfile . + +docker-build-distroless: docker-build + +docker-build-alpine: + @DOCKER_BUILDKIT=1 docker build \ + -t quasar:local-alpine \ + --build-arg GO_VERSION=$(GO_VERSION) \ + --build-arg RUNNER_IMAGE=$(RUNNER_BASE_IMAGE_ALPINE) \ + --build-arg GIT_VERSION=$(VERSION) \ + --build-arg GIT_COMMIT=$(COMMIT) \ + -f Dockerfile . + +docker-build-nonroot: + @DOCKER_BUILDKIT=1 docker build \ + -t quasar:local-nonroot \ + --build-arg GO_VERSION=$(GO_VERSION) \ + --build-arg RUNNER_IMAGE=$(RUNNER_BASE_IMAGE_NONROOT) \ + --build-arg GIT_VERSION=$(VERSION) \ + --build-arg GIT_COMMIT=$(COMMIT) \ + -f Dockerfile . + + +# This is not available to avoid missbehavior since it seems to be a bug in docker compose -p localenv: +# https://github.com/docker/compose/issues/10068 +# docker-compose-up-attached: ##@docker Run (and build if needed) env in docker compose. Attach if running in background. +# @echo "Launching local env with docker-compose" +# DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker compose -p localenv -f tests/docker/docker-compose.yml up + +docker-compose-up: ##@docker Run local env, build only if no images available + @echo "Launching local env, building images if not available" + DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker compose -p localenv -f tests/docker/docker-compose.yml up -d + +docker-compose-up-recreate: ##@docker DESTROY env containers and respawn them + @echo "Recreate local env (will destroy application state)" + DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker compose -p localenv -f tests/docker/docker-compose.yml up -d --force-recreate + +docker-compose-build: ##@docker Build new image if there are code changes, won't recreate containers. + @echo "Rebuilding image for local env" + DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker compose -p localenv -f tests/docker/docker-compose.yml build + +docker-compose-rebuild: docker-compose-build docker-compose-up-recreate ##@docker Recreate containers building new code if needed + @echo "Rebuilding images and restarting containers" + +docker-compose-stop: ##@docker Stop containers without deleting them + @echo "Stop docker containers without removing them" + DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker compose -p localenv -f tests/docker/docker-compose.yml stop + +docker-compose-down: ##@docker Stop AND DELETE delete the containers + @echo "Stopping docker containers and REMOVING THEM" + DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker compose -p localenv -f tests/docker/docker-compose.yml down + +docker-attach-quasar: ##@docker Connect to a terminal prompt in QUASAR node container + @echo "Connecting to quasar docker container" + docker exec -it localenv-quasar-1 /bin/bash + +docker-attach-osmosis: ##@docker Connect to a terminal prompt in OSMOSIS node container + @echo "Connecting to osmosis docker container" + docker exec -it localenv-osmosis-1 /bin/ash + +docker-attach-relayer: ##@docker Connect to a terminal prompt in RLY node container + @echo "Connecting to relayer docker container" + docker exec -it localenv-relayer-1 /bin/bash + +docker-test-e2e: docker-compose-up + @echo "Running e2e tests" + cd ./tests/shell/ && ./create_and_execute_contract.sh + + +############################################################################### +### Linting ### +############################################################################### + +lint: + @echo "--> Running linter" + @go run github.com/golangci/golangci-lint/cmd/golangci-lint run --timeout=10m + +.PHONY: all build-linux install format lint build \ + test test-all test-build test-cover test-unit test-race benchmark diff --git a/README.md b/README.md index f60d12aa0..db94b4bd3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Quasar -This is the official Quasar Labs repository. Quasar is building decentralized vaults for creating custom and sovereign investment vehicles in the Cosmos ecosystem and beyond. +This is the official Quasar Labs repository. +Quasar is a decentralized app-chain built for interchain asset management. Quasar is focused in utilizing the latest and contributing to building IBC features including: IBC features that we are developing on: @@ -8,7 +9,9 @@ IBC features that we are developing on: 2. Async Interchain Queries (Async - ICQ). 3. IBC hook middleware for token transfer. -Quasar is working hard to simplfy and add ease to collaborative investment with digital assets. We are creating a decentralized platform for creating custom, soverign vaults that can be molded into any imaginable investment financial instrument from ETFs, mutual fund, SPAC, or whatever. +Quasar is working hard to simplfy and add ease to collaborative investment with digital assets. + +We are creating a decentralized platform for creating custom, soverign vaults that can be molded into any imaginable investment financial instrument from ETFs, mutual fund, SPAC, or whatever. The galaxy is the limit. Our flagship product starts with vault that implements optimal LPing into pools on Osmosis DEX. @@ -25,13 +28,11 @@ The current codebase is experimental and undergoing continuous testing and audit make install ``` - -## Quasar Local Testnet (localnet) - -We have created several demo directories for the different usecases. You can find ./quasar_local.sh in demo/orion_manual_demo dir, and similar scripts in the other directories. - + ## Learn more -1. +1. https://www.quasar.fi/ +2. https://app.quasar.fi/ ## Attributions -1. x/qtransfer and x/epochs module are utilised from the osmosis x/ibc_hooks and x/epochs module. \ No newline at end of file + +x/qtransfer, x/epochs and x/tokenfactory module are utilised from the osmosis x/ibc_hooks, x/epochs and x/tokenfactory module. \ No newline at end of file diff --git a/app/app.go b/app/app.go index 2b2b65d2d..6d20cbcd3 100644 --- a/app/app.go +++ b/app/app.go @@ -3,12 +3,17 @@ package app import ( "fmt" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + "io" "net/http" "os" "path/filepath" "strings" + "github.com/quasarlabs/quasarnode/app/keepers" + v0 "github.com/quasarlabs/quasarnode/app/upgrades/v0" + appParams "github.com/quasarlabs/quasarnode/app/params" "github.com/quasarlabs/quasarnode/app/upgrades" @@ -34,6 +39,8 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/auth/vesting" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + authztypes "github.com/cosmos/cosmos-sdk/x/authz" + authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" "github.com/cosmos/cosmos-sdk/x/bank" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -94,8 +101,8 @@ import ( ibcporttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/quasarlabs/quasarnode/app/openapiconsole" "github.com/spf13/cast" - "github.com/quasarlabs/quasarnode/app/openapiconsole" abci "github.com/tendermint/tendermint/abci/types" tmjson "github.com/tendermint/tendermint/libs/json" "github.com/tendermint/tendermint/libs/log" @@ -123,6 +130,14 @@ import ( qosmokeeper "github.com/quasarlabs/quasarnode/x/qoracle/osmosis/keeper" qosmotypes "github.com/quasarlabs/quasarnode/x/qoracle/osmosis/types" qoraclemoduletypes "github.com/quasarlabs/quasarnode/x/qoracle/types" + + qvestingmodule "github.com/quasarlabs/quasarnode/x/qvesting" + qvestingmodulekeeper "github.com/quasarlabs/quasarnode/x/qvesting/keeper" + qvestingmoduletypes "github.com/quasarlabs/quasarnode/x/qvesting/types" + tfmodule "github.com/quasarlabs/quasarnode/x/tokenfactory" + tfbindings "github.com/quasarlabs/quasarnode/x/tokenfactory/bindings" + tfkeeper "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" + tftypes "github.com/quasarlabs/quasarnode/x/tokenfactory/types" // this line is used by starport scaffolding # stargate/app/moduleImport ) @@ -226,6 +241,10 @@ var ( // this line is used by starport scaffolding # stargate/app/moduleBasic wasm.AppModuleBasic{}, qtransfer.AppModuleBasic{}, + tfmodule.AppModuleBasic{}, + + qvestingmodule.AppModuleBasic{}, + authzmodule.AppModuleBasic{}, ) // module account permissions @@ -239,10 +258,11 @@ var ( ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, icatypes.ModuleName: nil, // this line is used by starport scaffolding # stargate/app/maccPerms - wasm.ModuleName: {authtypes.Burner}, + wasm.ModuleName: {authtypes.Burner}, + tftypes.ModuleName: {authtypes.Minter, authtypes.Burner}, } - Upgrades = []upgrades.Upgrade{} + Upgrades = []upgrades.Upgrade{v0.Upgrade} ) var ( @@ -264,6 +284,7 @@ func init() { // capabilities aren't needed for testing. type App struct { *baseapp.BaseApp + keepers.AppKeepers cdc *codec.LegacyAmino appCodec codec.Codec @@ -276,47 +297,6 @@ type App struct { tkeys map[string]*sdk.TransientStoreKey memKeys map[string]*sdk.MemoryStoreKey - // keepers - AccountKeeper authkeeper.AccountKeeper - BankKeeper bankkeeper.Keeper - CapabilityKeeper *capabilitykeeper.Keeper - StakingKeeper stakingkeeper.Keeper - SlashingKeeper slashingkeeper.Keeper - MintKeeper mintkeeper.Keeper - DistrKeeper distrkeeper.Keeper - GovKeeper govkeeper.Keeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.Keeper - ParamsKeeper paramskeeper.Keeper - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - EvidenceKeeper evidencekeeper.Keeper - TransferKeeper ibctransferkeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper - WasmKeeper wasm.Keeper - - // make scoped keepers public for test purposes - ScopedIBCKeeper capabilitykeeper.ScopedKeeper - ScopedTransferKeeper capabilitykeeper.ScopedKeeper - ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper - ScopedICAHostKeeper capabilitykeeper.ScopedKeeper - ScopedIntergammKeeper capabilitykeeper.ScopedKeeper - scopedQOracleKeeper capabilitykeeper.ScopedKeeper - ScopedWasmKeeper capabilitykeeper.ScopedKeeper - - QTransferKeeper qtransferkeeper.Keeper - EpochsKeeper *epochsmodulekeeper.Keeper - QOsmosisKeeper qosmokeeper.Keeper - QOracleKeeper qoraclemodulekeeper.Keeper - - ICAControllerKeeper icacontrollerkeeper.Keeper - ICAHostKeeper icahostkeeper.Keeper - // this line is used by starport scaffolding # stargate/app/keeperDeclaration - // transfer module - RawIcs20TransferAppModule transfer.AppModule - TransferStack *qtransfer.IBCMiddleware - Ics20WasmHooks *qtransfer.WasmHooks - HooksICS4Wrapper qtransfer.ICS4Middleware - // mm is the module manager mm *module.Manager @@ -373,6 +353,10 @@ func New( icahosttypes.StoreKey, wasm.StoreKey, qtransfertypes.StoreKey, + tftypes.StoreKey, + + qvestingmoduletypes.StoreKey, // TODO delete this if unused + authzkeeper.StoreKey, // this line is used by starport scaffolding # stargate/app/storeKey ) tkeys := sdk.NewTransientStoreKeys( @@ -385,6 +369,7 @@ func New( ) app := &App{ + AppKeepers: keepers.AppKeepers{}, BaseApp: bApp, cdc: cdc, appCodec: appCodec, @@ -556,6 +541,25 @@ func New( ) qtranserModule := qtransfer.NewAppModule(app.QTransferKeeper) + app.QVestingKeeper = *qvestingmodulekeeper.NewKeeper( + appCodec, + keys[qvestingmoduletypes.StoreKey], + keys[qvestingmoduletypes.MemStoreKey], + app.GetSubspace(qvestingmoduletypes.ModuleName), + + app.AccountKeeper, + app.BankKeeper, + ) + + qvestingModule := qvestingmodule.NewAppModule(appCodec, app.QVestingKeeper, app.AccountKeeper, app.BankKeeper) + + // Authz + app.AuthzKeeper = authzkeeper.NewKeeper( + app.keys[authzkeeper.StoreKey], + appCodec, + bApp.MsgServiceRouter(), + ) + // Set epoch hooks app.EpochsKeeper.SetHooks( epochsmoduletypes.NewMultiEpochHooks( @@ -563,6 +567,18 @@ func New( ), ) + /// Token factory Module + app.TfKeeper = tfkeeper.NewKeeper(keys[tftypes.StoreKey], + app.GetSubspace(tftypes.ModuleName), + app.AccountKeeper, + app.BankKeeper, + app.DistrKeeper, + ) + tfModule := tfmodule.NewAppModule(app.TfKeeper, + app.AccountKeeper, + app.BankKeeper, + ) + // create the wasm callback plugin // TODO_IMPORTANT - CALL BACK ACCOUNT @@ -577,7 +593,11 @@ func New( panic(fmt.Sprintf("error while reading wasm config: %s", err)) } - wasmOpts = append(owasm.RegisterCustomPlugins(app.QOracleKeeper, &bankkeeper.BaseKeeper{}, callback), wasmOpts...) + // AUDIT CHECK IS THIS TYPE ASSERTION FOR TYPE CASTING INTERFACE TO STRUCT SAFE? + tmpBankBaseKeeper := app.BankKeeper.(bankkeeper.BaseKeeper) + + wasmOpts = append(wasmOpts, owasm.RegisterCustomPlugins(app.QOracleKeeper, &tmpBankBaseKeeper, callback)...) + wasmOpts = append(wasmOpts, tfbindings.RegisterCustomPlugins(&tmpBankBaseKeeper, &app.TfKeeper)...) // The last arguments can contain custom message handlers, and custom query handlers, // if we want to allow any custom callbacks @@ -688,6 +708,11 @@ func New( qoracleModule, qtranserModule, icaModule, + + tfModule, + + qvestingModule, + authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), // this line is used by starport scaffolding # stargate/app/appModule ) @@ -719,6 +744,11 @@ func New( paramstypes.ModuleName, authtypes.ModuleName, wasm.ModuleName, + + tftypes.ModuleName, + + qvestingmoduletypes.ModuleName, + authztypes.ModuleName, ) app.mm.SetOrderEndBlockers(crisistypes.ModuleName, @@ -744,6 +774,11 @@ func New( genutiltypes.ModuleName, epochsmoduletypes.ModuleName, wasm.ModuleName, + + tftypes.ModuleName, + + qvestingmoduletypes.ModuleName, + authztypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -779,6 +814,10 @@ func New( // wasm after ibc transfer wasm.ModuleName, qtransfertypes.ModuleName, + tftypes.ModuleName, + + qvestingmoduletypes.ModuleName, + authztypes.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) @@ -787,7 +826,18 @@ func New( app.mm.RegisterServices(app.configurator) app.setupUpgradeHandlers() + upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() + if err != nil { + panic(fmt.Sprintf("failed to read upgrade info from disk %s", err)) + } + if upgradeInfo.Name == v0.UpgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + storeUpgrades := v0.Upgrade.StoreUpgrades + + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } + // app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) // create the simulation manager and define the order of the modules for deterministic simulations app.sm = module.NewSimulationManager( auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts), @@ -805,6 +855,7 @@ func New( ibc.NewAppModule(app.IBCKeeper), app.RawIcs20TransferAppModule, epochsModule, + //qvestingModule, TODO fix or remove // TODO fix qoracle testing for sim // qoracleModule, // TODO fix intergam genesis + testing first (right now, test code does not even compile...) @@ -859,7 +910,7 @@ func New( app.ScopedIBCKeeper = scopedIBCKeeper app.ScopedTransferKeeper = scopedTransferKeeper app.ScopedWasmKeeper = scopedWasmKeeper - app.scopedQOracleKeeper = scopedQOsmosisKeeper + app.ScopedQOracleKeeper = scopedQOsmosisKeeper app.ScopedICAControllerKeeper = scopedICAControllerKeeper app.ScopedICAHostKeeper = scopedICAHostKeeper // app.ScopedIntergammKeeper = scopedIntergammKeeper @@ -877,7 +928,7 @@ func (app *App) setupUpgradeHandlers() { app.mm, app.configurator, app.BaseApp, - // TODO pass the keepers necessary for the upgrades + &app.AppKeepers, ), ) } @@ -1056,6 +1107,10 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino // paramsKeeper.Subspace(intergammmoduletypes.ModuleName) paramsKeeper.Subspace(wasm.ModuleName) paramsKeeper.Subspace(qtransfertypes.ModuleName) + paramsKeeper.Subspace(tftypes.ModuleName) + + paramsKeeper.Subspace(qvestingmoduletypes.ModuleName) + paramsKeeper.Subspace(authztypes.ModuleName) // this line is used by starport scaffolding # stargate/app/paramSubspace return paramsKeeper diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go new file mode 100644 index 000000000..1efc312fb --- /dev/null +++ b/app/keepers/keepers.go @@ -0,0 +1,80 @@ +package keepers + +import ( + "github.com/CosmWasm/wasmd/x/wasm" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" + feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + icacontrollerkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/keeper" + icahostkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + epochsmodulekeeper "github.com/quasarlabs/quasarnode/x/epochs/keeper" + qoraclemodulekeeper "github.com/quasarlabs/quasarnode/x/qoracle/keeper" + qosmokeeper "github.com/quasarlabs/quasarnode/x/qoracle/osmosis/keeper" + "github.com/quasarlabs/quasarnode/x/qtransfer" + qtransferkeeper "github.com/quasarlabs/quasarnode/x/qtransfer/keeper" + qvestingmodulekeeper "github.com/quasarlabs/quasarnode/x/qvesting/keeper" + tfmodulekeeper "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" +) + +type AppKeepers struct { + // Special keepers + ParamsKeeper paramskeeper.Keeper + CapabilityKeeper *capabilitykeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.Keeper + + // make scoped keepers public for test purposes + ScopedIBCKeeper capabilitykeeper.ScopedKeeper + ScopedTransferKeeper capabilitykeeper.ScopedKeeper + ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper + ScopedICAHostKeeper capabilitykeeper.ScopedKeeper + ScopedIntergammKeeper capabilitykeeper.ScopedKeeper + ScopedQOracleKeeper capabilitykeeper.ScopedKeeper + ScopedWasmKeeper capabilitykeeper.ScopedKeeper + + // "Normal" keepers + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + StakingKeeper stakingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper + MintKeeper mintkeeper.Keeper + DistrKeeper distrkeeper.Keeper + GovKeeper govkeeper.Keeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidencekeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + WasmKeeper wasm.Keeper + QTransferKeeper qtransferkeeper.Keeper + EpochsKeeper *epochsmodulekeeper.Keeper + QOsmosisKeeper qosmokeeper.Keeper + QOracleKeeper qoraclemodulekeeper.Keeper + QVestingKeeper qvestingmodulekeeper.Keeper + TfKeeper tfmodulekeeper.Keeper + AuthzKeeper authzkeeper.Keeper + ICAControllerKeeper icacontrollerkeeper.Keeper + ICAHostKeeper icahostkeeper.Keeper + + // IBC modules + // transfer module + RawIcs20TransferAppModule transfer.AppModule + TransferStack *qtransfer.IBCMiddleware + Ics20WasmHooks *qtransfer.WasmHooks + HooksICS4Wrapper qtransfer.ICS4Middleware + + // this line is used by starport scaffolding # stargate/app/keeperDeclaration +} diff --git a/app/upgrades/types.go b/app/upgrades/types.go index ab4d3d21d..0375e9cb2 100644 --- a/app/upgrades/types.go +++ b/app/upgrades/types.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/quasarlabs/quasarnode/app/keepers" abci "github.com/tendermint/tendermint/abci/types" ) @@ -28,6 +29,7 @@ type Upgrade struct { mm *module.Manager, configurator module.Configurator, bam BaseAppParamManager, + keepers *keepers.AppKeepers, ) upgradetypes.UpgradeHandler // Store upgrades, should be used for any new modules introduced, new modules deleted, or store names renamed. diff --git a/app/upgrades/v0/constants.go b/app/upgrades/v0/constants.go new file mode 100644 index 000000000..610386725 --- /dev/null +++ b/app/upgrades/v0/constants.go @@ -0,0 +1,21 @@ +package v0 + +import ( + store "github.com/cosmos/cosmos-sdk/store/types" + authztypes "github.com/cosmos/cosmos-sdk/x/authz/keeper" + "github.com/quasarlabs/quasarnode/app/upgrades" + qvestingtypes "github.com/quasarlabs/quasarnode/x/qvesting/types" + tftypes "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +// UpgradeName defines the on-chain upgrade name for the Quasar chain v1.0.0 upgrade. +const UpgradeName = "v1" + +var Upgrade = upgrades.Upgrade{ + UpgradeName: UpgradeName, + CreateUpgradeHandler: CreateUpgradeHandler, + StoreUpgrades: store.StoreUpgrades{ + Added: []string{qvestingtypes.StoreKey, tftypes.StoreKey, authztypes.StoreKey}, + Deleted: []string{}, + }, +} diff --git a/app/upgrades/v0/export_test.go b/app/upgrades/v0/export_test.go new file mode 100644 index 000000000..636c40a94 --- /dev/null +++ b/app/upgrades/v0/export_test.go @@ -0,0 +1,10 @@ +package v0 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + qvestingkeeper "github.com/quasarlabs/quasarnode/x/qvesting/keeper" +) + +func SetQVestingParams(ctx sdk.Context, icqKeeper *qvestingkeeper.Keeper) { + setQVestingParams(ctx, icqKeeper) +} diff --git a/app/upgrades/v0/upgrades.go b/app/upgrades/v0/upgrades.go new file mode 100644 index 000000000..a788c898a --- /dev/null +++ b/app/upgrades/v0/upgrades.go @@ -0,0 +1,37 @@ +package v0 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/quasarlabs/quasarnode/app/keepers" + "github.com/quasarlabs/quasarnode/app/upgrades" + qvestingkeeper "github.com/quasarlabs/quasarnode/x/qvesting/keeper" + qvestingtypes "github.com/quasarlabs/quasarnode/x/qvesting/types" + tfkeeper "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" + tftypes "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + bpm upgrades.BaseAppParamManager, + keepers *keepers.AppKeepers, +) upgradetypes.UpgradeHandler { + return func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + setQVestingParams(ctx, &keepers.QVestingKeeper) + setTfParams(ctx, &keepers.TfKeeper) + + return mm.RunMigrations(ctx, configurator, fromVM) + } +} + +func setQVestingParams(ctx sdk.Context, qvestingKeeper *qvestingkeeper.Keeper) { + qvestingParams := qvestingtypes.DefaultParams() + qvestingKeeper.SetParams(ctx, qvestingParams) +} + +func setTfParams(ctx sdk.Context, tfKeeper *tfkeeper.Keeper) { + tfParams := tftypes.DefaultParams() + tfKeeper.SetParams(ctx, tfParams) +} diff --git a/cmd/quasarnoded/cmd/config.go b/cmd/quasarnoded/cmd/config.go index 235bb5f82..f85944232 100644 --- a/cmd/quasarnoded/cmd/config.go +++ b/cmd/quasarnoded/cmd/config.go @@ -6,6 +6,21 @@ import ( "github.com/quasarlabs/quasarnode/app" ) +func InitTestConfig() { + // Set prefixes + accountPubKeyPrefix := app.AccountAddressPrefix + "pub" + validatorAddressPrefix := app.AccountAddressPrefix + "valoper" + validatorPubKeyPrefix := app.AccountAddressPrefix + "valoperpub" + consNodeAddressPrefix := app.AccountAddressPrefix + "valcons" + consNodePubKeyPrefix := app.AccountAddressPrefix + "valconspub" + + // Set and seal config + config := sdk.GetConfig() + config.SetBech32PrefixForAccount(app.AccountAddressPrefix, accountPubKeyPrefix) + config.SetBech32PrefixForValidator(validatorAddressPrefix, validatorPubKeyPrefix) + config.SetBech32PrefixForConsensusNode(consNodeAddressPrefix, consNodePubKeyPrefix) +} + func initSDKConfig() { // Set prefixes accountPubKeyPrefix := app.AccountAddressPrefix + "pub" diff --git a/config.yml b/config.yml deleted file mode 100644 index ec99a8332..000000000 --- a/config.yml +++ /dev/null @@ -1,80 +0,0 @@ -accounts: - - name: alice - mnemonic: edge victory hurry slight dog exit company bike hill erupt shield aspect turkey retreat stairs summer sadness crush absorb draft viable orphan chuckle exhibit - coins: ["20000token", "200000000stake", "1000000000uqsr"] - - name: bob - mnemonic: harvest ill mean warfare gospel slide tragic palace model excess surprise distance voyage change bus grant special artwork win width group dwarf today jar - coins: ["10000token", "100000000stake", "1000000000uqsr"] -validator: - name: alice - staked: "100000000uqsr" -genesis: - chain_id: "quasar" - app_state: - staking: - params: - bond_denom: uqsr - intergamm: - params: - osmo_token_transfer_channels: - osmosis-test: channel-1 - osmosis: channel-1 - dest_to_intr_zone_map: - osmosis-01: cosmos - intr_rcvrs: - - zone_info: - chain_id: 'cosmos' - connection_id: 'connection-02' - rcvr_address: 'cosmos1ppkxa0hxak05tcqq3338k76xqxy2qse96uelcu' - next_zone_route_map: - osmosis-01: - local_zone_id: osmosis-01 - connection_id: 'connection-01' - chain_id: "osmosis" - transfer_channel_id: "channel-01" - osmosis-02: - local_zone_id: osmosis-02 - connection_id: 'connection-02' - chain_id: "osmosis2" - transfer_channel_id: "channel-02" - orion: - params: - enabled: false - lp_epoch_id: day #override day for testing - mgmt_fee_per: '0.003000000000000000' - perf_fee_per: '0.020000000000000000' - destination_chain_id: osmosis - white_listed_pools : [1,2,3] - osmosis_local_info: - local_zone_id : osmosis-01 - chain_id: 'osmosis' - connection_id: 'connection-01' - qoracle: - params: - oracleAccounts: 'quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec' - qbank: - params: - enabled: true - min_orion_epoch_denom_dollar_deposit: '100.000000000000000000' - orion_epoch_identifier: day #override day for testing - white_listed_denoms_in_orion: - - onehop_osmo: ibc/BE1BB42D4BE3C30D50B68D7C41DB4DFCE9678E8EF8C539F6E6A9345048894FCC - onehop_quasar: ibc/BE1BB42D4BE3C30D50B68D7C41DB4DFCE9678E8EF8C539F6E6A9345048894FCC - origin_name: uatom -host: - rpc: ":26659" - p2p: ":26661" - prof: ":6061" - grpc: ":9095" - grpc-web: ":8091" - api: ":1311" - frontend: ":8081" - dev-ui: ":12351" -client: - openapi: - path: "docs/static/openapi.yml" -faucet: - name: bob - coins: ["5token", "100000stake", "10000uqsr"] -init: - home: "$HOME/.quasar" \ No newline at end of file diff --git a/demos/authz-demo/authz_gov_demo.sh b/demos/authz-demo/authz_gov_demo.sh new file mode 100755 index 000000000..6ad795778 --- /dev/null +++ b/demos/authz-demo/authz_gov_demo.sh @@ -0,0 +1,44 @@ +#!/bin/sh +set -o xtrace +BINARY=quasarnoded +HOME_QSR=$HOME/.quasarnode +CHAIN_ID=quasar +NODE="--node tcp://localhost:26659" + + +ALICE=$($BINARY keys show alice --keyring-backend test -a --home $HOME_QSR) +BOB=$($BINARY keys show bob --keyring-backend test -a --home $HOME_QSR) +TX_FLAG="--chain-id=quasar --gas-prices 0.1uqsr --gas auto --gas-adjustment 1.3 -b block --node tcp://localhost:26659 --keyring-backend test --home $HOME_QSR --output json -y" +QUERY_FLAG="--node tcp://localhost:26659 --output json" + +# alice to create a text based gov proposal on quasar chain, that alice wants to get voted by bob on behalf of alice. + +echo "Alice creating gov proposal on chain." +$BINARY tx gov submit-proposal --title="Test Authorization" --description="Is Bob authorized to vote?" --type="Text" --deposit="10000000uqsr" --from $ALICE $TX_FLAG + +echo "Alice grant Vote auth to bob." +$BINARY tx authz grant $BOB generic --msg-type /cosmos.gov.v1beta1.MsgVote --from $ALICE $TX_FLAG + +echo "Query auth grant status." +$BINARY query authz grants $ALICE $BOB /cosmos.gov.v1beta1.MsgVote $QUERY_FLAG + +echo "Alice generate unsinged tx., the expected sequence number is 3 for the below tx." # NEED TO CHECK WHY? +# If you are running multiple tests, and runs. the expected sequence number might got changed accordingly you need to use the expected sequence number. +$BINARY tx gov vote 1 yes --from $ALICE --generate-only $TX_FLAG --sequence 3 > tx.json + +echo "bob is signing tx on behalf on alice" +$BINARY tx authz exec tx.json --from bob $TX_FLAG + +echo "query if the vote was done by alice" +$BINARY query gov vote 1 $ALICE $QUERY_FLAG + + +sleep 3 + +echo "Revoke the auth" +$BINARY tx authz revoke $BOB /cosmos.gov.v1beta1.MsgVote --from alice $TX_FLAG + +echo "query if the auth revoke was successful. it should show below error. \nError: rpc error: code = NotFound desc = rpc error: code = NotFound desc = no authorization found for /cosmos.gov.v1beta1.MsgVote type: key not found" +$BINARY query authz grants $ALICE $BOB /cosmos.gov.v1beta1.MsgVote $QUERY_FLAG + + diff --git a/demos/authz-demo/quasar_localnet.sh b/demos/authz-demo/quasar_localnet.sh new file mode 100755 index 000000000..8054f95e8 --- /dev/null +++ b/demos/authz-demo/quasar_localnet.sh @@ -0,0 +1,93 @@ +#!/bin/sh + +## This script helps to create a basic version of the quasar chain genesis file for development purposes. +## However it will need some manual modifications before you start the chain to incorporate the custom fields. + +# Configure variables +BINARY=quasarnoded +HOME_QSR=$HOME/.quasarnode +CHAIN_ID=quasar + +ALICE="edge victory hurry slight dog exit company bike hill erupt shield aspect turkey retreat stairs summer sadness crush absorb draft viable orphan chuckle exhibit" +BOB="harvest ill mean warfare gospel slide tragic palace model excess surprise distance voyage change bus grant special artwork win width group dwarf today jar" +USER_1="guard cream sadness conduct invite crumble clock pudding hole grit liar hotel maid produce squeeze return argue turtle know drive eight casino maze host" +USER_2="fuel obscure melt april direct second usual hair leave hobby beef bacon solid drum used law mercy worry fat super must ritual bring faculty" +RELAYER_ACC="old cinnamon boy hurry pipe upset exhibit title copy squirrel grit eye love toy cotton connect inhale cost quarter mistake ahead endless bless license" + +ALICE_GENESIS_COINS=20000token,200000000stake,1000000000uqsr +BOB_GENESIS_COINS=10000token,100000000stake,1000000000uqsr +USER_1_GENESIS_COINS=10000000000stake,10000000000uqsr +USER_2_GENESIS_COINS=10000000000stake,10000000000uqsr +RELAYER_ACC_GENESIS_COINS=10000000uqsr + +# Remove previous setup +rm -rf $HOME_QSR + +$BINARY init $CHAIN_ID --chain-id $CHAIN_ID --home $HOME_QSR + +# Bootstrap the quasar local network with single node + +echo $ALICE | $BINARY keys add alice --keyring-backend test --recover --home $HOME_QSR +echo $BOB | $BINARY keys add bob --keyring-backend test --recover --home $HOME_QSR +echo $USER_1 | $BINARY keys add user1 --keyring-backend test --recover --home $HOME_QSR +echo $USER_2 | $BINARY keys add user2 --keyring-backend test --recover --home $HOME_QSR +echo $RELAYER_ACC | $BINARY keys add relayer_acc --keyring-backend test --recover --home $HOME_QSR + +$BINARY add-genesis-account $($BINARY keys show alice --keyring-backend test -a) $ALICE_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY add-genesis-account $($BINARY keys show bob --keyring-backend test -a) $BOB_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY add-genesis-account $($BINARY keys show user1 --keyring-backend test -a) $USER_1_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY add-genesis-account $($BINARY keys show user2 --keyring-backend test -a) $USER_2_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY add-genesis-account $($BINARY keys show relayer_acc --keyring-backend test -a) $RELAYER_ACC_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY gentx alice 100000000uqsr --chain-id $CHAIN_ID --keyring-backend test --home $HOME_QSR --keyring-backend test +$BINARY collect-gentxs --home $HOME_QSR + +# Check platform +platform='unknown' +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + platform='linux' +elif [ "$unamestr" = 'Darwin' ]; then + platform='macos' +fi + +if [ $platform = 'linux' ]; then + sed -i 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0uqsr"/g' $HOME_QSR/config/app.toml + sed -i 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +elif [ $platform = 'macos' ]; then + sed -i'.original' -e 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/minimum-gas-prices = ""/minimum-gas-prices = "0uatom"/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i'.original' -e 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +else + echo "only linux and macos platforms are supported, if you are using other platforms you should probably improve this script." + exit 1 +fi + +cp $HOME_QSR/config/genesis.json $HOME_QSR/config/genesis_original.json +cat $HOME_QSR/config/genesis_original.json | + jq '.app_state.crisis.constant_fee.denom="uqsr"' | + jq '.app_state.staking.params.bond_denom="uqsr"' | + jq '.app_state.mint.params.mint_denom="uqsr"' | + jq '.app_state.gov.deposit_params.min_deposit=[{denom:"uqsr",amount:"1"}]' | + jq '.app_state.gov.voting_params.voting_period="600s"' | + jq '.app_state.gov.tally_params={quorum:"0.000000000000000001",threshold:"0.5",veto_threshold:"0.334"}' | + jq '.app_state.qoracle.osmosis_genesis_state.params.authorized_channel="channel-0"' >$HOME_QSR/config/genesis.json + +# Start +$BINARY start --home $HOME_QSR > quasar.log 2>&1 & diff --git a/demos/authz-demo/run_authz_gov_demo.sh b/demos/authz-demo/run_authz_gov_demo.sh new file mode 100755 index 000000000..6c7b0160a --- /dev/null +++ b/demos/authz-demo/run_authz_gov_demo.sh @@ -0,0 +1,7 @@ +#!/bin/sh +pkill quasarnoded + +./quasar_localnet.sh + +sleep 10 +./authz_gov_demo.sh > log.log 2>&1 diff --git a/demos/bandchain-config/README.md b/demos/bandchain-config/README.md deleted file mode 100644 index 18c216913..000000000 --- a/demos/bandchain-config/README.md +++ /dev/null @@ -1,50 +0,0 @@ -The purpose of this demo is to demonstrate the ibc connection establishment between bandchain testnet and quasar localnet. And also checking the stable price query update in the quasar chain. - - -1. Remove previous relayer configuration by running the following command -``` -rm -rf ~/.ignite/relayer -``` - -2. Start the chain with default config -``` -ignite chain serve --reset-once -v -``` - -3. Configure a channel for bandchain testnet - -Cross check the value of each field based on your current chain setup. Bandchain also regularly -updating their testnet so its rpc and faucet address are also changing. - -``` -ignite relayer configure -a \ ---target-rpc "https://rpc.laozi-testnet5.bandchain.org" \ ---target-faucet "https://laozi-testnet5.bandchain.org/faucet" \ ---target-port "oracle" \ ---target-gasprice "0uband" \ ---target-gaslimit 5000000 \ ---target-prefix "band" \ ---target-version "bandchain-1" \ ---source-rpc "http://localhost:26659" \ ---source-faucet "http://localhost:4500" \ ---source-port "qoracle" \ ---source-gasprice "0.0stake" \ ---source-gaslimit 300000 \ ---source-prefix "quasar" \ ---source-version "bandchain-1" -``` - -1. Start the relayer -``` -ignite relayer connect -``` -Wait for the channel and relayer to come online - -5. Watch for changes in state -Use the right api port based on config.yml file. -In this repo it is 1311 -``` -http://localhost:1317/quasarlabs/quasarnode/qoracle/state -or -http://localhost:1311/quasarlabs/quasarnode/qoracle/state -``` diff --git a/demos/ica-packet-forward/README.md b/demos/ica-packet-forward/README.md deleted file mode 100644 index 6baec5a2f..000000000 --- a/demos/ica-packet-forward/README.md +++ /dev/null @@ -1,78 +0,0 @@ -Start a quasar node - -``` -ignite chain serve --config demos/ica-packet-forward/quasar.yml --reset-once -v -``` - -Clone gaia from this repo (https://github.com/quasar-finance/gaia/tree/bugfix/replace_default_transfer_with_router_module) and run it by copying the the cosmos.yml file to gaia project root and running the following command: - -``` -cd ../gaia -ignite chain serve --config cosmos.yml --reset-once -v -``` - -(For now we use another instance of quasar as osmosis since icahost is not implemented yet in osmosis) - -``` -ignite chain serve --config demos/ica-packet-forward/osmosis.yml --reset-once -v -``` - -``` -cp ./demos/ica-packet-forward/hermes_config.toml ~/.hermes/config.toml -``` - -Using hermes v0.15.0 - -``` -hermes keys restore --mnemonic "jungle law popular reunion festival horn divorce quarter image gather october weird slide trend resource render abuse food tomorrow multiply price fun ask quarter" quasar - -hermes keys restore --mnemonic "blade trap agent boy note critic jazz nuclear eight lion pipe fresh tourist make broken inquiry close agree usual human stock move remain swim" cosmos - -hermes keys restore --mnemonic "act scale exhibit enough swamp vivid bleak eagle giggle brass desert debris network scrub hazard fame salon normal over between inform advance sick dinner" osmosis -``` - -Create ibc connection between quasar and osmosis for ICA usage - -``` -hermes create connection quasar osmosis -``` - -Create transfer channels between osmosis <-> cosmos and cosmos <-> quasar - -``` -hermes create channel osmosis --chain-b cosmos --port-a transfer --port-b transfer --new-client-connection - -hermes create channel cosmos --chain-b quasar --port-a transfer --port-b transfer --new-client-connection -``` - -``` -hermes start -``` - -Register interchain account - -``` -quasarnoded tx intergamm register-account connection-0 --chain-id=quasar --node=tcp://localhost:26659 --home ~/.qsr --from alice -``` - -Query the interchain account address on osmosis - -``` -quasarnoded query intergamm interchain-account-from-address connection-0 quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node=tcp://localhost:26659 -``` - -Send some tokens to the interchain account address on osmosis - -``` -quasarnoded tx bank send alice quasar1hphwfu3yjf82z8xpcl6e05gzkjwjmu8ts2m97mdk62feuqm77f2sj52eta 10uosmo --chain-id=osmosis --node=tcp://localhost:26669 --home ~/.osmo --from alice -``` - -Issue the interchain tx to ibc transfer some tokens to quasar from interchain account on osmosis through cosmos - -``` -quasarnoded tx intergamm forward-ibc-transfer connection-0 transfer channel-0 10uosmo transfer channel-1 cosmos1e3geute48fzym40um7gw2kjt87q7nkeel7mept quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --chain-id=quasar --node=tcp://localhost:26659 --home ~/.qsr --from alice -``` - -Check balance of quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec from the link below, it should contain 10ibc/C9B459D627233FC6E5049A27B5465D76C7F69D7FCB7F843EAC2B6A38B668F9F1 - -http://localhost:1311/bank/balances/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec \ No newline at end of file diff --git a/demos/ica-packet-forward/cosmos.yml b/demos/ica-packet-forward/cosmos.yml deleted file mode 100644 index 2c0d9d422..000000000 --- a/demos/ica-packet-forward/cosmos.yml +++ /dev/null @@ -1,30 +0,0 @@ -accounts: - - name: alice - mnemonic: edge victory hurry slight dog exit company bike hill erupt shield aspect turkey retreat stairs summer sadness crush absorb draft viable orphan chuckle exhibit - coins: ["20000000uatom", "2000000000stake"] - - name: bob - mnemonic: harvest ill mean warfare gospel slide tragic palace model excess surprise distance voyage change bus grant special artwork win width group dwarf today jar - coins: ["10000000uatom", "1000000000stake"] - - name: relayer_acc - coins: ["10000stake"] - address: cosmos14ahzv9ldtfn7ktgnd0m8k70d6l080lvdlrrsth -validator: - name: alice - staked: "100000000stake" -faucet: - host: ":4501" - name: bob - coins: ["1000000uatom", "100000000stake"] -host: - rpc: ":26559" - p2p: ":26662" - prof: ":6062" - grpc: ":9096" - grpc-web: ":8092" - api: ":1312" - frontend: ":8082" - dev-ui: ":12352" -genesis: - chain_id: "cosmos" -init: - home: "$HOME/.cosmos" diff --git a/demos/ica-packet-forward/hermes_config.toml b/demos/ica-packet-forward/hermes_config.toml deleted file mode 100644 index 9b624f5db..000000000 --- a/demos/ica-packet-forward/hermes_config.toml +++ /dev/null @@ -1,178 +0,0 @@ -# The global section has parameters that apply globally to the relayer operation. -[global] - -# Specify the verbosity for the relayer logging output. Default: 'info' -# Valid options are 'error', 'warn', 'info', 'debug', 'trace'. -log_level = 'debug' - - -# Specify the mode to be used by the relayer. [Required] -[mode] - -# Specify the client mode. -[mode.clients] - -# Whether or not to enable the client workers. [Required] -enabled = true - -# Whether or not to enable periodic refresh of clients. [Default: true] -# Note: Even if this is disabled, clients will be refreshed automatically if -# there is activity on a connection or channel they are involved with. -refresh = true - -# Whether or not to enable misbehaviour detection for clients. [Default: false] -misbehaviour = true - -# Specify the connections mode. -[mode.connections] - -# Whether or not to enable the connection workers for handshake completion. [Required] -enabled = true - -# Specify the channels mode. -[mode.channels] - -# Whether or not to enable the channel workers for handshake completion. [Required] -enabled = true - -# Specify the packets mode. -[mode.packets] - -# Whether or not to enable the packet workers. [Required] -enabled = true - -# Parametrize the periodic packet clearing feature. -# Interval (in number of blocks) at which pending packets -# should be eagerly cleared. A value of '0' will disable -# periodic packet clearing. [Default: 100] -clear_interval = 100 - -# Whether or not to clear packets on start. [Default: false] -clear_on_start = true - -# Toggle the transaction confirmation mechanism. -# The tx confirmation mechanism periodically queries the `/tx_search` RPC -# endpoint to check that previously-submitted transactions -# (to any chain in this config file) have delivered successfully. -# Experimental feature. Affects telemetry if set to false. -# [Default: true] -tx_confirmation = true - -# The REST section defines parameters for Hermes' built-in RESTful API. -# https://hermes.informal.systems/rest.html -[rest] - -# Whether or not to enable the REST service. Default: false -enabled = true - -# Specify the IPv4/6 host over which the built-in HTTP server will serve the RESTful -# API requests. Default: 127.0.0.1 -host = '127.0.0.1' - -# Specify the port over which the built-in HTTP server will serve the restful API -# requests. Default: 3000 -port = 3000 - - -# The telemetry section defines parameters for Hermes' built-in telemetry capabilities. -# https://hermes.informal.systems/telemetry.html -[telemetry] - -# Whether or not to enable the telemetry service. Default: false -enabled = true - -# Specify the IPv4/6 host over which the built-in HTTP server will serve the metrics -# gathered by the telemetry service. Default: 127.0.0.1 -host = '127.0.0.1' - -# Specify the port over which the built-in HTTP server will serve the metrics gathered -# by the telemetry service. Default: 3001 -port = 3001 - -[[chains]] -id = 'osmosis' -rpc_addr = 'http://127.0.0.1:26679' -grpc_addr = 'http://127.0.0.1:9096' -websocket_addr = 'ws://127.0.0.1:26679/websocket' -rpc_timeout = '10s' -account_prefix = 'osmo' -key_name = 'osmosiskey' -store_prefix = 'ibc' -default_gas = 100000 -max_gas = 3000000 -gas_price = { price = 0.001, denom = 'uosmo' } -#gas_multiplier = 1.1 -gas_adjustment = 0.1 -max_msg_num = 30 -max_tx_size = 2097152 -clock_drift = '5s' -max_block_time = '10s' -trusting_period = '14days' -trust_threshold = { numerator = '1', denominator = '3' } -address_type = { derivation = 'cosmos' } - -[[chains]] -id = 'cosmos' -rpc_addr = 'http://127.0.0.1:26669' -grpc_addr = 'http://127.0.0.1:9097' -websocket_addr = 'ws://127.0.0.1:26669/websocket' -rpc_timeout = '10s' -account_prefix = 'cosmos' -key_name = 'cosmoskey' -store_prefix = 'ibc' -default_gas = 100000 -max_gas = 3000000 -gas_price = { price = 0.001, denom = 'uatom' } -#gas_multiplier = 1.1 -gas_adjustment = 0.1 -max_msg_num = 30 -max_tx_size = 2097152 -clock_drift = '5s' -max_block_time = '10s' -trusting_period = '14days' -trust_threshold = { numerator = '1', denominator = '3' } -address_type = { derivation = 'cosmos' } - -[[chains]] -id = 'quasar' -rpc_addr = 'http://127.0.0.1:26659' -grpc_addr = 'http://127.0.0.1:9095' -websocket_addr = 'ws://127.0.0.1:26659/websocket' -rpc_timeout = '10s' -account_prefix = 'quasar' -key_name = 'quasarkey' -store_prefix = 'ibc' -default_gas = 100000 -max_gas = 3000000 -gas_price = { price = 0.001, denom = 'uqsr' } -#gas_multiplier = 1.1 -gas_adjustment = 0.1 -max_msg_num = 30 -max_tx_size = 2097152 -clock_drift = '5s' -max_block_time = '10s' -trusting_period = '14days' -trust_threshold = { numerator = '1', denominator = '3' } -address_type = { derivation = 'cosmos' } - -[[chains]] -id = 'band-laozi-testnet5' -rpc_addr = 'https://rpc.laozi-testnet5.bandchain.org:443' -grpc_addr = 'https://laozi-testnet5.bandchain.org' -websocket_addr = 'ws://rpc.laozi-testnet5.bandchain.org:443/websocket' -rpc_timeout = '10s' -account_prefix = 'band' -key_name = 'bandkey' -store_prefix = 'ibc' -default_gas = 100000 -max_gas = 3000000 -gas_price = { price = 0.001, denom = 'uband' } -#gas_multiplier = 1.1 -gas_adjustment = 0.1 -max_msg_num = 30 -max_tx_size = 2097152 -clock_drift = '5s' -max_block_time = '10s' -trusting_period = '14days' -trust_threshold = { numerator = '1', denominator = '3' } -address_type = { derivation = 'cosmos' } diff --git a/demos/ica-packet-forward/osmosis.yml b/demos/ica-packet-forward/osmosis.yml deleted file mode 100644 index 9c8e29a99..000000000 --- a/demos/ica-packet-forward/osmosis.yml +++ /dev/null @@ -1,35 +0,0 @@ -accounts: - - name: alice - mnemonic: edge victory hurry slight dog exit company bike hill erupt shield aspect turkey retreat stairs summer sadness crush absorb draft viable orphan chuckle exhibit - coins: ["20000000uosmo", "2000000000stake"] - - name: bob - mnemonic: harvest ill mean warfare gospel slide tragic palace model excess surprise distance voyage change bus grant special artwork win width group dwarf today jar - coins: ["10000000uosmo", "1000000000stake"] - - name: relayer_acc - coins: ["10000stake"] - address: quasar139njd402zqj368sk65y753ppp4hxr926pkhrkk -validator: - name: alice - staked: "100000000stake" -faucet: - host: ":4502" - name: bob - coins: ["1000000uosmo", "100000000stake"] -host: - rpc: ":26669" - p2p: ":26663" - prof: ":6063" - grpc: ":9097" - grpc-web: ":8093" - api: ":1313" - frontend: ":8083" - dev-ui: ":12353" -genesis: - chain_id: "osmosis" - app_state: - interchainaccounts: - host_genesis_state: - params: - allow_messages: ["/ibc.applications.transfer.v1.MsgTransfer"] -init: - home: "$HOME/.osmo" diff --git a/demos/ica-packet-forward/quasar.yml b/demos/ica-packet-forward/quasar.yml deleted file mode 100644 index 0da2c6e1e..000000000 --- a/demos/ica-packet-forward/quasar.yml +++ /dev/null @@ -1,30 +0,0 @@ -accounts: - - name: alice - mnemonic: edge victory hurry slight dog exit company bike hill erupt shield aspect turkey retreat stairs summer sadness crush absorb draft viable orphan chuckle exhibit - coins: ["20000000qsr", "2000000000stake"] - - name: bob - mnemonic: harvest ill mean warfare gospel slide tragic palace model excess surprise distance voyage change bus grant special artwork win width group dwarf today jar - coins: ["10000000qsr", "1000000000stake"] - - name: relayer_acc - coins: ["10000stake"] - address: quasar1tshnze3yrtv3hk9x536p7znpxeckd4v9ha0trg -validator: - name: alice - staked: "100000000stake" -faucet: - host: ":4500" - name: bob - coins: ["1000000qsr", "100000000stake"] -host: - rpc: ":26659" - p2p: ":26661" - prof: ":6061" - grpc: ":9095" - grpc-web: ":8091" - api: ":1311" - frontend: ":8081" - dev-ui: ":12351" -genesis: - chain_id: "quasar" -init: - home: "$HOME/.qsr" diff --git a/demos/orion-manual-demo/band_testnet_init.sh b/demos/orion-manual-demo/band_testnet_init.sh deleted file mode 100755 index 45def3851..000000000 --- a/demos/orion-manual-demo/band_testnet_init.sh +++ /dev/null @@ -1,59 +0,0 @@ -## This script helps to initialize accounts on the testnet of the band for test purposes. - -usage() { - echo "usage: $0 [-h | --use-faucet]" - exit -} - -while [ "$1" ]; -do - arg="$1" - case $arg in - --use-faucet) - shift - echo use_faucet - use_faucet=true - ;; - -h) - shift - usage - ;; - *) - shift - echo "error: unknown argument" - usage - ;; - esac -done - -# Configure variables -BINARY=bandd -HOME_BAND=$HOME/.band -CHAIN_ID=band -ALICE="use struggle faith reason method camp stay hair rabbit click across stadium there intact catalog segment drill summer oak tell tell success giraffe direct" -BOB="universe include catalog auction allow digital purity glimpse trash desert mom sea cry exchange question weekend post rival mutual scale staff law modify flee" -RELAYER_ACC="machine danger crush duck always will liberty popular security shoulder bargain day repair focus fog evoke market gossip love curious question kingdom armor crazy" - -# Remove previous setup -rm -rf $HOME_BAND - -# Bootstrap the quasar local network with single node - -echo $ALICE | $BINARY keys add alice --keyring-backend test --recover -echo $BOB | $BINARY keys add bob --keyring-backend test --recover -echo $RELAYER_ACC | $BINARY keys add relayer_acc --keyring-backend test --recover - -if [ "$use_faucet" = true ] -then - # Get some tokens from faucet - FAUCET_ADDR="https://laozi-testnet5.bandchain.org/faucet" - curl -X POST -d '{"address":"'$($BINARY keys show alice --keyring-backend test -a)'"}' $FAUCET_ADDR ; echo - curl -X POST -d '{"address":"'$($BINARY keys show bob --keyring-backend test -a)'"}' $FAUCET_ADDR ; echo - curl -X POST -d '{"address":"'$($BINARY keys show relayer_acc --keyring-backend test -a)'"}' $FAUCET_ADDR ; echo -fi - -# Check balances -RPC_ADDR="https://rpc.laozi-testnet5.bandchain.org:443" -$BINARY q bank balances $($BINARY keys show alice --keyring-backend test -a) --node $RPC_ADDR -$BINARY q bank balances $($BINARY keys show bob --keyring-backend test -a) --node $RPC_ADDR -$BINARY q bank balances $($BINARY keys show relayer_acc --keyring-backend test -a) --node $RPC_ADDR diff --git a/demos/orion-manual-demo/complete_zone_info_map-proposal.json b/demos/orion-manual-demo/complete_zone_info_map-proposal.json deleted file mode 100644 index 4f4a9a55a..000000000 --- a/demos/orion-manual-demo/complete_zone_info_map-proposal.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "title": "denom_to_native_zone_id_map Param Change", - "description": "Update CompleteZoneInfoMap", - "changes": [ - { - "subspace": "intergamm", - "key": "CompleteZoneInfoMap", - "value": { - "osmosis": { - "zone_route_info": { - "zone_id": "quasar", - "chain_id": "quasar", - "counterparty_zone_id": "osmosis", - "counterparty_chain_id": "osmosis", - "connection_id": "connection-1", - "port_id": "transfer", - "channel_id": "channel-1", - "counterparty_connection_id": "connection-0", - "counterparty_port_id": "transfer", - "counterparty_channel_id": "channel-1", - "counterparty_version": "" - }, - "next_zone_route_map": {} - }, - "cosmos": { - "zone_route_info": { - "zone_id": "quasar", - "chain_id": "quasar", - "counterparty_zone_id": "cosmos", - "counterparty_chain_id": "cosmos", - "connection_id": "connection-0", - "port_id": "transfer", - "channel_id": "channel-0", - "counterparty_connection_id": "connection-0", - "counterparty_port_id": "transfer", - "counterparty_channel_id": "channel-0", - "counterparty_version": "" - }, - "next_zone_route_map": { - "osmosis": { - "zone_id": "cosmos", - "chain_id": "cosmos", - "counterparty_zone_id": "osmosis", - "counterparty_chain_id": "osmosis", - "connection_id": "connection-1", - "port_id": "transfer", - "channel_id": "channel-1", - "counterparty_connection_id": "connection-1", - "counterparty_port_id": "transfer", - "counterparty_channel_id": "channel-0", - "counterparty_version": "" - } - } - } - } - } - ], - "deposit": "1uqsr" -} diff --git a/demos/orion-manual-demo/demo.md b/demos/orion-manual-demo/demo.md index 957523f0c..8cd7893f5 100644 --- a/demos/orion-manual-demo/demo.md +++ b/demos/orion-manual-demo/demo.md @@ -694,36 +694,4 @@ osmosisd tx ibc-transfer transfer transfer channel-1 quasar1sqlsc5024sszglyh7psw osmosisd q bank balances osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq --node tcp://localhost:26679 quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 ``` - - -## Set the Price of in quasarnode -``` -quasarnoded tx qoracle stable-price ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 "1" --from alice --node tcp://localhost:26659 --chain-id quasar --home ~/quasar-demo/quasar/demos/orion-manual-demo/run/home/quasarnode/ -``` - -## Request Deposit -``` -quasarnoded tx qbank request-deposit "MID" "orion" 110ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 Days_7 --from alice --node tcp://localhost:26659 --chain-id quasar --home ~/quasar-demo/quasar/demos/orion-manual-demo/run/home/quasarnode/ -``` -- Post check - -Note that, it will also packet forward the deposited tokens to osmosis via cosmos. Check the -osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq address for initial version ( hardcoded in code ) - -## Other sample commands -### Query port info from intergamm module -``` -quasarnoded q intergamm get-port-info osmosis transfer --node tcp://localhost:26659 -portInfo: - channelID: channel-2 - connectionID: connection-1 - counterpartyChannelID: channel-1 - portID: transfer -``` -``` -quasarnoded q intergamm get-port-info osmosis icacontroller-quasar14yjkz7yxapuee3d7qkhwzlumwrarayfh0pycxc --node tcp://localhost:26659 -portInfo: - channelID: channel-1 - connectionID: connection-1 - counterpartyChannelID: channel-2 - portID: icacontroller-quasar14yjkz7yxapuee3d7qkhwzlumwrarayfh0pycxc -``` + \ No newline at end of file diff --git a/demos/orion-manual-demo/deploy_and_test_ica.sh b/demos/orion-manual-demo/deploy_and_test_ica.sh deleted file mode 100755 index 3c1d1f0b1..000000000 --- a/demos/orion-manual-demo/deploy_and_test_ica.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh - -CHAIN_ID="quasar" -TESTNET_NAME="quasar" -FEE_DENOM="uqsr" -# STAKE_DENOM="urock" -BECH32_HRP="quas" -WASMD_VERSION="v0.23.0" -CONFIG_DIR=".wasmd" -BINARY="wasmd" -COSMJS_VERSION="v0.27.1" -GENESIS_URL="https://raw.githubusercontent.com/CosmWasm/testnets/master/cliffnet-1/config/genesis.json" -RPC="http://127.0.0.1:26659" -# RPC="https://rpc.cliffnet.cosmwasm.com:443" -LCD="https://lcd.cliffnet.cosmwasm.com" -FAUCET="https://faucet.cliffnet.cosmwasm.com" -# https://rpc-edgenet.dev-osmosis.zone/ -# https://lcd-edgenet.dev-osmosis.zone/ -NODE="--node $RPC" -TXFLAG="$NODE --chain-id $CHAIN_ID --gas-prices 10$FEE_DENOM --gas auto --gas-adjustment 1.3" - -INIT="{}" -MSG='{"register_interchain_account":{"connection_id":"connection-1"}}' - -cd ../../smart-contracts - -# docker run --rm -v "$(pwd)":/code --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry cosmwasm/rust-optimizer:0.12.6 - -echo "Running store code" -RES=$(quasarnoded tx wasm store artifacts/intergamm_bindings_test.wasm --from alice -y --output json -b block $TXFLAG) -CODE_ID=$(echo $RES | jq -r '.logs[0].events[-1].attributes[0].value') -echo "Got CODE_ID = $CODE_ID" - -echo "Deploying contract" -# swallow output -OUT=$(quasarnoded tx wasm instantiate $CODE_ID "$INIT" --from alice --label "my first contract" --gas-prices 10$FEE_DENOM --gas auto --gas-adjustment 1.3 -b block -y --no-admin $NODE --chain-id $CHAIN_ID) -ADDR=$(quasarnoded query wasm list-contract-by-code $CODE_ID --output json $NODE | jq -r '.contracts[0]') -echo "Got address of deployed contract = $ADDR" - -echo "Executing register ica message... ('$MSG')" -quasarnoded tx wasm execute $ADDR "$MSG" --from alice --gas-prices 10$FEE_DENOM --gas auto --gas-adjustment 1.3 $NODE --chain-id $CHAIN_ID - -cd - \ No newline at end of file diff --git a/demos/orion-manual-demo/forwarding-demo.md b/demos/orion-manual-demo/forwarding-demo.md deleted file mode 100644 index 16527fa10..000000000 --- a/demos/orion-manual-demo/forwarding-demo.md +++ /dev/null @@ -1,28 +0,0 @@ -This demo shows us how to set up an environment and test packet forwarding. - -1. Run the steps described in the `run_integrated_testnet.md` to initialize the chains and the channels between them. - -2. Check the initial balances -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -gaiad q bank balances cosmos1ppkxa0hxak05tcqq3338k76xqxy2qse96uelcu --node tcp://localhost:26669 -osmosisd q bank balances osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq --node tcp://localhost:26679 -``` - -3. Transfer some atom to quasar and gaia -``` -gaiad tx ibc-transfer transfer transfer channel-0 "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec" 100uatom --from alice --chain-id cosmos --home ~/.gaia/ --node tcp://localhost:26669 --keyring-backend test -y - -gaiad tx ibc-transfer transfer transfer channel-1 "osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq" 100uatom --from alice --chain-id cosmos --home ~/.gaia/ --node tcp://localhost:26669 --keyring-backend test -y -``` - -4. Optionally you can transfer some atom back to gaia to see if the quasar->gaia route works. -``` -quasarnoded tx ibc-transfer transfer transfer channel-0 "cosmos1ppkxa0hxak05tcqq3338k76xqxy2qse96uelcu" 5ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -``` - -5. Finally transfer some atom from quasar to osmosis via gaia -``` -quasarnoded tx ibc-transfer transfer transfer channel-0 "cosmos1ppkxa0hxak05tcqq3338k76xqxy2qse96uelcu|transfer/channel-1:osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq" 20ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -``` - diff --git a/demos/orion-manual-demo/osmosis_denom_to_quasar_denom_map-proposal.json b/demos/orion-manual-demo/osmosis_denom_to_quasar_denom_map-proposal.json deleted file mode 100644 index 7edba59ef..000000000 --- a/demos/orion-manual-demo/osmosis_denom_to_quasar_denom_map-proposal.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "osmosis_denom_to_quasar_denom_map Param Change", - "description": "Update OsmosisDenomToQuasarDenomMap", - "changes": [ - { - "subspace": "intergamm", - "key": "OsmosisDenomToQuasarDenomMap", - "value": { - "ibc/C18695C91D20F11FEE3919D7822B34651277CA84550EF33379E823AD9702B257": "uqsr", - "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2", - "uosmo": "ibc/0471F1C4E7AFD3F07702BEF6DC365268D64570F7C1FDC98EA6098DD6DE59817B" - } - } - ], - "deposit": "1uqsr" -} diff --git a/demos/orion-manual-demo/quasar_denom_to_native_zone_id_map-proposal.json b/demos/orion-manual-demo/quasar_denom_to_native_zone_id_map-proposal.json deleted file mode 100644 index 49a451956..000000000 --- a/demos/orion-manual-demo/quasar_denom_to_native_zone_id_map-proposal.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "quasar_denom_to_native_zone_id_map Param Change", - "description": "Update QuasarDenomToNativeZoneIdMap", - "changes": [ - { - "subspace": "intergamm", - "key": "QuasarDenomToNativeZoneIdMap", - "value": { - "uqsr": "quasar", - "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2": "cosmos", - "ibc/0471F1C4E7AFD3F07702BEF6DC365268D64570F7C1FDC98EA6098DD6DE59817B": "osmosis" - } - } - ], - "deposit": "1uqsr" -} diff --git a/demos/orion-manual-demo/test-intergamm-forwarding-and-request-deposit-demo.md b/demos/orion-manual-demo/test-intergamm-forwarding-and-request-deposit-demo.md deleted file mode 100644 index 233af0cb9..000000000 --- a/demos/orion-manual-demo/test-intergamm-forwarding-and-request-deposit-demo.md +++ /dev/null @@ -1,92 +0,0 @@ -This demo demonstrates how to set intergamm params through gov procedures, -make request deposit txs, -and test if the deposits are actually transferred to osmosis properly from quasar. - -1. Run the steps described in the `run_integrated_testnet.md` to initialize the chains and the channels between them. - -2. First we need to verify connection and channel IDs among chains. - All channels of a chain can be listed by: -``` -hermes query channels osmosis -hermes query channels cosmos -hermes query channels quasar -``` -Focus on channels whose port ID is "transfer". -For these channels view their details by: -``` -hermes query channel ends osmosis transfer -``` -For example: -``` -hermes query channel ends osmosis transfer channel-0 -``` -Check their chain_id, counterparty_chain_id, channel_id, and counterparty_channel_id. -the channel IDs should be as follows: -quasar->osmosis channel-1 -osmosis->quasar channel-1 -quasar->cosmos channel-0 -cosmos->quasar channel-0 -cosmos->osmosis channel-1 -osmosis->cosmos channel-0 - -3. If the channel IDs found in previous step are different, - edit the `complete_zone_info_map-proposal.json` accordingly. - -4. Check the initial balances (of account alice). -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -gaiad q bank balances cosmos1ppkxa0hxak05tcqq3338k76xqxy2qse96uelcu --node tcp://localhost:26669 -osmosisd q bank balances osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq --node tcp://localhost:26679 -``` - -5. Transfer some uatom to quasar and osmosis to find its ibc denoms in those chains. -``` -gaiad tx ibc-transfer transfer transfer channel-0 "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec" 10000uatom --from alice --chain-id cosmos --home ~/.gaia/ --node tcp://localhost:26669 --keyring-backend test -y - -gaiad tx ibc-transfer transfer transfer channel-1 "osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq" 100uatom --from alice --chain-id cosmos --home ~/.gaia/ --node tcp://localhost:26669 --keyring-backend test -y -``` - -6. Check the balances (of account alice) on quasar and osmosis and note the ibc denom of uatom in both chains. -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -osmosisd q bank balances osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq --node tcp://localhost:26679 -``` - -7. If ibc denom of uatom on quasar is different from "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2", -modify the denom_to_native_zone_id_map-proposal.json file and change it. - -8. Transfer some uosmo to quasar to find its ibc denom. -``` -osmosisd tx ibc-transfer transfer transfer channel-1 "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec" 10000uosmo --from alice --chain-id osmosis --home ~/.osmosis/ --node tcp://localhost:26679 --keyring-backend test -y -``` - -9. Check the balances (of account alice) on quasar and note the ibc denom of uosmo. -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -``` - -10. If ibc denom of uosmo on quasar is different from "ibc/0471F1C4E7AFD3F07702BEF6DC365268D64570F7C1FDC98EA6098DD6DE59817B", -modify the denom_to_native_zone_id_map-proposal.json file and change it. - -11. Run the change_quasar_param.sh script to submit param change proposals and vote on them. -You need to wait 90 seconds until these changes takes effect. - -12. Set stable prices of uqsr, uosmo, uatom. -``` -quasarnoded tx qoracle stable-price uqsr 1.3 --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -quasarnoded tx qoracle stable-price ibc/0471F1C4E7AFD3F07702BEF6DC365268D64570F7C1FDC98EA6098DD6DE59817B 1.3 --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -quasarnoded tx qoracle stable-price ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 1.3 --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -``` - -13. Submit request deposit txs. -``` -quasarnoded tx qbank request-deposit orion 1000uqsr Days_7 "" --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -quasarnoded tx qbank request-deposit orion 1000ibc/0471F1C4E7AFD3F07702BEF6DC365268D64570F7C1FDC98EA6098DD6DE59817B Days_7 "" --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -quasarnoded tx qbank request-deposit orion 1000ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 Days_7 "" --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -``` - -14. Finally, check the balance of orion ICA on osmosis: -``` -osmosisd q bank balances osmo1dzgzjwvtu77x7p36xh9ut0xpek34y706rt6p5djn038455qtxjmsg4akrw --node tcp://localhost:26679 -``` - diff --git a/demos/orion-manual-demo/test-intergamm-token-transfer.md b/demos/orion-manual-demo/test-intergamm-token-transfer.md deleted file mode 100644 index 1a1765264..000000000 --- a/demos/orion-manual-demo/test-intergamm-token-transfer.md +++ /dev/null @@ -1,116 +0,0 @@ -This demo demonstrates how to set intergamm params through gov procedures -and how to test intergamm token transferred. - -There are 6 cases that need to be tested: -1. transfer quasar-native token (e.g. uqsr) from quasar to osmosis -2. transfer quasar-native token (e.g. uqsr) from osmosis to quasar -3. transfer osmosis-native token (e.g. uosmo) from quasar to osmosis -4. transfer osmosis-native token (e.g. uosmo) from osmosis to quasar -5. transfer 3rd party token (e.g. uatom) from quasar to osmosis -6. transfer 3rd party token (e.g. uatom) from osmosis to quasar - -# Preparing the test setup - -1. Run the steps described in the `run_integrated_testnet.md` to initialize the chains and the channels between them. - -2. Run the steps described in the `verify-channel-ids-guide.md` and check if your channel IDs match what we assume in these guides. - -3. Run the steps described in the `verify-ibc-denoms-guide.md` and check if the IBC denoms in your test setup match what we assume in these guides. - -4. Check the initial balances of alice on quasar. -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -``` - -5. Set the intergamm module parameters by running `change_quasar_param.sh`. - This scripts submits needed gov proposals and votes on them. - You need to wait 90 seconds until these changes takes effect. - -6. Register an ICA for alice on osmosis (necessary for testing cases #2, #4, and #6). -``` -quasarnoded tx intergamm register-ica-on-zone osmosis --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -b block -``` -Wait for about 30 seconds until the ICA and its channels are fully initialized and opened. -If Successful the following command should output the ICA address of alice on osmosis: -``` -quasarnoded q intergamm ica-address-on-zone $(quasarnoded keys show -a alice --keyring-backend test) osmosis -``` - -6. Register an ICA for alice on the native zone of uatom (necessary for testing cases #5 and #6). -``` -quasarnoded tx intergamm register-ica-on-denom-native-zone ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -b block -``` -Wait for about 30 seconds until the ICA and its channels are fully initialized and opened. -If Successful the following command should output the ICA address of alice on osmosis: -``` -quasarnoded q intergamm ica-address-on-denom-native-zone $(quasarnoded keys show -a alice --keyring-backend test) ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 -``` - -7. Check quasar balance of alice and also her ICA balance on osmosis -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -osmosisd q bank balances osmo1hphwfu3yjf82z8xpcl6e05gzkjwjmu8ts2m97mdk62feuqm77f2skm6qcy --node tcp://localhost:26679 -``` - -# Testing case #1 and #2 (uqsr) - -1. Test case #1 (uqsr from quasar to osmosis): -``` -quasarnoded tx intergamm send-token-to-ica osmosis 5000uqsr --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -b block -``` -This command sends tokens from alice account on quasar to her ICA on osmosis. -You can also use `quasarnoded tx intergamm send-token` to send tokens to an arbitrary account on osmosis, -but for testing case #2 you need to send to alice's ICA. - -2. Check balances (after a few seconds): -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -osmosisd q bank balances osmo1hphwfu3yjf82z8xpcl6e05gzkjwjmu8ts2m97mdk62feuqm77f2skm6qcy --node tcp://localhost:26679 -``` - -3. Test case #2 (uqsr from osmosis to quasar): -``` -quasarnoded tx intergamm transmit-ica-transfer quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 4000ibc/C18695C91D20F11FEE3919D7822B34651277CA84550EF33379E823AD9702B257 --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -b block -``` - -# Testing case #3 and #4 (uosmo) - -1. Test case #3 (uosmo from quasar to osmosis): -``` -quasarnoded tx intergamm send-token-to-ica osmosis 5000ibc/0471F1C4E7AFD3F07702BEF6DC365268D64570F7C1FDC98EA6098DD6DE59817B --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -b block -``` -This command sends tokens from alice account on quasar to her ICA on osmosis. -You can also use `quasarnoded tx intergamm send-token` to send tokens to an arbitrary account on osmosis, -but for testing case #4 you need to send to alice's ICA. - -2. Check balances (after a few seconds): -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -osmosisd q bank balances osmo1hphwfu3yjf82z8xpcl6e05gzkjwjmu8ts2m97mdk62feuqm77f2skm6qcy --node tcp://localhost:26679 -``` - -3. Test case #4 (uosmo from osmosis to quasar): -``` -quasarnoded tx intergamm transmit-ica-transfer quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 4000uosmo --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -b block -``` - -# Testing case #5 and #6 (uatom) - -1. Test case #5 (uatom from quasar to osmosis): -``` -quasarnoded tx intergamm send-token-to-ica osmosis 5000ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -b block -``` -This command sends tokens from alice account on quasar to her ICA on osmosis. -You can also use `quasarnoded tx intergamm send-token` to send tokens to an arbitrary account on osmosis, -but for testing case #6 you need to send to alice's ICA. - -2. Check balances (after a few seconds): -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -osmosisd q bank balances osmo1hphwfu3yjf82z8xpcl6e05gzkjwjmu8ts2m97mdk62feuqm77f2skm6qcy --node tcp://localhost:26679 -``` - -3. Test case #6 (uatom from osmosis to quasar): -``` -quasarnoded tx intergamm transmit-ica-transfer quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 4000ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -b block -``` diff --git a/demos/orion-manual-demo/verify-channel-ids-guide.md b/demos/orion-manual-demo/verify-channel-ids-guide.md deleted file mode 100644 index a74d3d939..000000000 --- a/demos/orion-manual-demo/verify-channel-ids-guide.md +++ /dev/null @@ -1,30 +0,0 @@ -This purpose of this guide is to demonstrate how to find the channel IDs in your test setup and -find out if they match what we expect in the demos of this directory. - -1. First we need to verify channel IDs among chains. - All channels of a chain can be listed by: -``` -hermes query channels osmosis -hermes query channels cosmos -hermes query channels quasar -``` -Focus on channels whose port ID is "transfer". -For these channels view their details by: -``` -hermes query channel ends osmosis transfer -``` -For example: -``` -hermes query channel ends osmosis transfer channel-0 -``` -Check their chain_id, counterparty_chain_id, channel_id, and counterparty_channel_id. -the channel IDs should be as follows: -quasar->osmosis channel-1 -osmosis->quasar channel-1 -quasar->cosmos channel-0 -cosmos->quasar channel-0 -cosmos->osmosis channel-1 -osmosis->cosmos channel-0 - -2. If the channel IDs found in previous step are different, - edit the `complete_zone_info_map-proposal.json` accordingly. diff --git a/demos/orion-manual-demo/verify-ibc-denoms-guide.md b/demos/orion-manual-demo/verify-ibc-denoms-guide.md deleted file mode 100644 index 7c6dca3ec..000000000 --- a/demos/orion-manual-demo/verify-ibc-denoms-guide.md +++ /dev/null @@ -1,55 +0,0 @@ -This purpose of this guide is to demonstrate how to find -the IBC denoms of uqsr, uosmo, and uatom in other chains in your test setup and -find out if they match what we expect in the demos of this directory. - -Our expectation: -* uqsr on osmosis: ibc/C18695C91D20F11FEE3919D7822B34651277CA84550EF33379E823AD9702B257 -* uosmo on quasar: ibc/0471F1C4E7AFD3F07702BEF6DC365268D64570F7C1FDC98EA6098DD6DE59817B -* uatom on quasar: inc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 -* uatom on osmosis: inc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 - -Note: generally uatom should hae different denoms on quasar and osmosis. -The reason they're the same here is that it arrives via the same port and channel IDs. - -1. Check the initial balances (of account alice). -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -gaiad q bank balances cosmos1ppkxa0hxak05tcqq3338k76xqxy2qse96uelcu --node tcp://localhost:26669 -osmosisd q bank balances osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq --node tcp://localhost:26679 -``` - -2. Transfer some uqsr to osmosis to find its IBC denom. -``` -quasarnoded tx ibc-transfer transfer transfer channel-1 osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq 10000uqsr --from alice --chain-id quasar --home ~/.quasarnode/ --node tcp://localhost:26659 --keyring-backend test -y -``` - -3. Check the balances (of account alice) on osmosis and note the IBC denom of uqsr. -``` -osmosisd q bank balances osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq --node tcp://localhost:26679 -``` - -4. Transfer some uosmo to quasar to find its IBC denom. -``` -osmosisd tx ibc-transfer transfer transfer channel-1 quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 10000uosmo --from alice --chain-id osmosis --home ~/.osmosis/ --node tcp://localhost:26679 --keyring-backend test -y -``` - -5. Check the balances (of account alice) on quasar and note the IBC denom of uosmo. -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -``` - -6. Transfer some uatom to quasar and osmosis to find its IBC denoms in those chains. -``` -gaiad tx ibc-transfer transfer transfer channel-0 quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 10000uatom --from alice --chain-id cosmos --home ~/.gaia/ --node tcp://localhost:26669 --keyring-backend test -y -gaiad tx ibc-transfer transfer transfer channel-1 osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq 10000uatom --from alice --chain-id cosmos --home ~/.gaia/ --node tcp://localhost:26669 --keyring-backend test -y -``` - -7. Check the balances (of account alice) on quasar and osmosis and note the IBC denom of uatom in both chains. -``` -quasarnoded q bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 -osmosisd q bank balances osmo1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq --node tcp://localhost:26679 -``` - -8. If the IBC denoms found in previous steps are different from the expectations listed in the beginning, - edit the `quasar_denom_to_native_zone_id_map-proposal.json` and - `osmosis_denom_to_quasar_denom_map-proposal` accordingly. diff --git a/demos/osmosis-config/tf_localnet.sh b/demos/osmosis-config/tf_localnet.sh new file mode 100755 index 000000000..e82bac02d --- /dev/null +++ b/demos/osmosis-config/tf_localnet.sh @@ -0,0 +1,83 @@ +# Configure variables +BINARY=toked +HOME_OSMOSIS=$HOME/.tf +CHAIN_ID=tf-1 +ALICE="cruise scene law sea push expose scorpion wire trick repair wave quote task dose inner denial alpha favorite certain blouse motion flash split lunch" +BOB="lizard garlic canyon winner cheese tent drip task because ecology clay bridge junk critic track artefact gather harsh deliver unit vacant earth diesel stool" +USER_1="guard cream sadness conduct invite crumble clock pudding hole grit liar hotel maid produce squeeze return argue turtle know drive eight casino maze host" +USER_2="fuel obscure melt april direct second usual hair leave hobby beef bacon solid drum used law mercy worry fat super must ritual bring faculty" +RELAYER_ACC="rabbit garlic monitor wish pony magic budget someone room torch celery empower word assume digital rack electric weapon urban foot sketch jelly wet myself" +ALICE_GENESIS_COINS=10000000000000uosmo,2000000000stake,20000000uatom +BOB_GENESIS_COINS=10000000000000uosmo,1000000000stake +USER_1_GENESIS_COINS=10000000000stake,10000000000uosmo +USER_2_GENESIS_COINS=10000000000stake,10000000000uosmo +RELAYER_ACC_GENESIS_COINS=10000000uosmo + +echo $HOME_OSMOSIS + +rm -rf $HOME_OSMOSIS +# Bootstrap +$BINARY init $CHAIN_ID --chain-id $CHAIN_ID --home $HOME_OSMOSIS + +echo $ALICE | $BINARY keys add alice --keyring-backend test --recover --home $HOME_OSMOSIS +echo $BOB | $BINARY keys add bob --keyring-backend test --recover --home $HOME_OSMOSIS +echo $USER_1 | $BINARY keys add user1 --keyring-backend test --recover --home $HOME_OSMOSIS +echo $USER_2 | $BINARY keys add user2 --keyring-backend test --recover --home $HOME_OSMOSIS +echo $RELAYER_ACC | $BINARY keys add relayer_acc --keyring-backend test --recover --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show alice --keyring-backend test -a --home $HOME_OSMOSIS) $ALICE_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show bob --keyring-backend test -a --home $HOME_OSMOSIS) $BOB_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show user1 --keyring-backend test -a --home $HOME_OSMOSIS) $USER_1_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show user2 --keyring-backend test -a --home $HOME_OSMOSIS) $USER_2_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show relayer_acc --keyring-backend test -a --home $HOME_OSMOSIS) $RELAYER_ACC_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY gentx alice 10000000uosmo --chain-id $CHAIN_ID --keyring-backend test --home $HOME_OSMOSIS +$BINARY collect-gentxs --home $HOME_OSMOSIS + +# Check platform +platform='unknown' +unamestr=`uname` +if [ "$unamestr" = 'Linux' ]; then + platform='linux' +elif [ "$unamestr" = 'Darwin' ]; then + platform='macos' +fi + +if [ $platform = 'linux' ]; then + sed -i 's/enable = false/enable = true/g' $HOME_OSMOSIS/config/app.toml + sed -i 's/swagger = false/swagger = true/g' $HOME_OSMOSIS/config/app.toml + sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0uosmo"/g' $HOME_OSMOSIS/config/app.toml + sed -i 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26679"+g' $HOME_OSMOSIS/config/config.toml + sed -i 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26679"+g' $HOME_OSMOSIS/config/client.toml + sed -i 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26662"+g' $HOME_OSMOSIS/config/config.toml + sed -i 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6062"+g' $HOME_OSMOSIS/config/config.toml + sed -i 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9096"+g' $HOME_OSMOSIS/config/app.toml + sed -i 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8092"+g' $HOME_OSMOSIS/config/app.toml + sed -i 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1312"+g' $HOME_OSMOSIS/config/app.toml + sed -i 's+address = ":8080"+address = ":8082"+g' $HOME_OSMOSIS/config/app.toml +elif [ $platform = 'macos' ]; then + sed -i'.original' -e 's/enable = false/enable = true/g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's/swagger = false/swagger = true/g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's/minimum-gas-prices = ""/minimum-gas-prices = "0uosmo"/g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26679"+g' $HOME_OSMOSIS/config/config.toml + sed -i'.original' -e 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26679"+g' $HOME_OSMOSIS/config/client.toml + sed -i'.original' -e 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26662"+g' $HOME_OSMOSIS/config/config.toml + sed -i'.original' -e 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6062"+g' $HOME_OSMOSIS/config/config.toml + sed -i'.original' -e 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9096"+g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8092"+g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1312"+g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's+address = ":8080"+address = ":8082"+g' $HOME_OSMOSIS/config/app.toml +else + echo "only linux and macos platforms are supported, if you are using other platforms you should probably improve this script." + exit 1 +fi + +cp $HOME_OSMOSIS/config/genesis.json $HOME_OSMOSIS/config/genesis_original.json +cat $HOME_OSMOSIS/config/genesis_original.json | + jq '.app_state.crisis.constant_fee.denom="uosmo"' | + jq '.app_state.staking.params.bond_denom="uosmo"' | + jq '.app_state.mint.params.mint_denom="uosmo"' | + jq '.app_state.gov.voting_params.voting_period="30s"' | + jq '.app_state.gov.deposit_params.min_deposit=[{denom:"uosmo",amount:"1"}]' | + jq '.app_state.gov.tally_params={quorum:"0.000000000000000001",threshold:"0.5",veto_threshold:"0.334"}' > $HOME_OSMOSIS/config/genesis.json + +# Start +$BINARY start --home $HOME_OSMOSIS > tf.log 2>&1 & diff --git a/demos/tokenfactory/README.md b/demos/tokenfactory/README.md new file mode 100644 index 000000000..88fe314d2 --- /dev/null +++ b/demos/tokenfactory/README.md @@ -0,0 +1,106 @@ +# Token factory demo guide + +This demo guide follow the instructions provided by token factory binding implementation in +https://github.com/CosmosContracts/token-bindings/ + +You can look into that for more information, steps are reproduced here for custom to the quasar chain binary. +## Testing steps with smart contract + +### Steps 1 - checkout the token binding codebase +```bash +git clone git@github.com:CosmosContracts/token-bindings.git + +``` + +### Build +#### Wasm compile +```bash +cd contracts/tokenfactory +rustup default stable +cargo wasm +``` + +#### Optimized compilation +Note - Remove the target directory from base directory and inside the tokenfactory directory. + +```bash +sudo docker run --rm -v "$(pwd)":/code --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry cosmwasm/workspace-optimizer:0.13.0 +``` +It will generate artifacts directory in the project root. And check if the artifacts +directory contains the newly build .wasm files. +```bash +cd artifacts +``` + +### Upload the artifacts +```bash +TX=$(quasarnoded tx wasm store tokenfactory.wasm --from alice --chain-id=quasar --gas-prices 0.1uqsr --keyring-backend test --home ~/.quasarnode --gas auto --gas-adjustment 1.3 -b block --output json -y --node tcp://localhost:26659 | jq -r '.txhash') +CODE_ID=$(quasarnoded query tx $TX --node tcp://localhost:26659 --output json | jq -r '.logs[0].events[-1].attributes[1].value') +echo "Your contract code_id is $CODE_ID" +``` + +### Instantiate the contract +```bash + +quasarnoded tx wasm instantiate $CODE_ID "{}" --amount 50000uqsr --label "Token Factory Contract" --from alice --keyring-backend test --home ~/.quasarnode --chain-id quasar --gas-prices 0.1uqsr --gas auto --gas-adjustment 1.3 -b block -y --no-admin --node tcp://localhost:26659 + +CONTRACT_ADDR=$(quasarnoded query wasm list-contract-by-code $CODE_ID --node tcp://localhost:26659 --output json | jq -r '.contracts[0]') +echo "Your contract address is $CONTRACT_ADDR" +``` + +### Execute & Queries + +#### Generate schema + +```bash +cd contracts/tokenfactory +cargo schema # generates schema in the contracts/tokenfactory/schema folder + +``` + +#### Create denom + + +```bash +quasarnoded tx wasm execute $CONTRACT_ADDR '{ "create_denom": { "subdenom": "mydenom" } }' --from alice --amount 1000000000uqsr -b block --keyring-backend test --home ~/.quasarnode --chain-id quasar --node tcp://localhost:26659 + +quasarnoded q bank total --denom factory/$CONTRACT_ADDR/mydenom --node tcp://localhost:26659 +# You should see this: +# amount: "0" +#denom: factory/osmo1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtqcm3670/mydenom +``` +#### mint +BOB=$(quasarnoded keys show bob --keyring-backend test -a) +```bash +quasarnoded tx wasm execute $CONTRACT_ADDR "{ \"mint_tokens\": {\"amount\": \"100\", \"denom\": \"factory/${CONTRACT_ADDR}/mydenom\", \"mint_to_address\": \"$BOB\"}}" --from alice --keyring-backend test --home ~/.quasarnode --chain-id quasar --node tcp://localhost:26659 -b block +quasarnoded q bank balances $BOB --node tcp://localhost:26659 +quasarnoded q bank total --denom factory/$CONTRACT_ADDR/mydenom --node tcp://localhost:26659 +``` + + +#### burn ( only contract can burn as of now) +1. Pre-Mint tokens to contract address. +2. Burn from contract address. +```bash + +quasarnoded tx wasm execute $CONTRACT_ADDR "{ \"mint_tokens\": {\"amount\": \"100\", \"denom\": \"factory/${CONTRACT_ADDR}/mydenom\", \"mint_to_address\": \"$CONTRACT_ADDR\"}}" --from alice --keyring-backend test --home ~/.quasarnode --chain-id quasar --node tcp://localhost:26659 -b block +quasarnoded tx wasm execute $CONTRACT_ADDR "{ \"burn_tokens\": {\"amount\": \"50\", \"denom\": \"factory/${CONTRACT_ADDR}/mydenom\", \"burn_from_address\": \"\"}}" --from alice --keyring-backend test --home ~/.quasarnode --chain-id quasar --node tcp://localhost:26659 -b block +quasarnoded q bank total --denom factory/$CONTRACT_ADDR/mydenom --node tcp://localhost:26659 +quasarnoded q bank balances $CONTRACT_ADDR --node tcp://localhost:26659 +``` + + +### change Admin + +```bash +quasarnoded q tokenfactory denom-authority-metadata factory/quasar14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sy9numu/mydenom --node tcp://localhost:26659 + + quasarnoded tx wasm execute $CONTRACT_ADDR "{ \"change_admin\": {\"denom\": \"factory/${CONTRACT_ADDR}/mydenom\", \"new_admin_address\": \"$BOB\"}}" --from alice --keyring-backend test --home ~/.quasarnode --chain-id quasar --node tcp://localhost:26659 -b block + +``` + +### Get denom +```bash + +quasarnoded query wasm contract-state smart $CONTRACT_ADDR "{ \"get_denom\": {\"creator_address\": \"${CONTRACT_ADDR}\", \"subdenom\": \"mydenom\" }}" --node tcp://localhost:26659 +``` \ No newline at end of file diff --git a/demos/tokenfactory/quasar_localnet.sh b/demos/tokenfactory/quasar_localnet.sh new file mode 100755 index 000000000..2aba7443f --- /dev/null +++ b/demos/tokenfactory/quasar_localnet.sh @@ -0,0 +1,93 @@ +#!/bin/sh + +## This script helps to create a basic version of the quasar chain genesis file for development purposes. +## However it will need some manual modifications before you start the chain to incorporate the custom fields. + +# Configure variables +BINARY=quasarnoded +HOME_QSR=$HOME/.quasarnode +CHAIN_ID=quasar + +ALICE="edge victory hurry slight dog exit company bike hill erupt shield aspect turkey retreat stairs summer sadness crush absorb draft viable orphan chuckle exhibit" +BOB="harvest ill mean warfare gospel slide tragic palace model excess surprise distance voyage change bus grant special artwork win width group dwarf today jar" +USER_1="guard cream sadness conduct invite crumble clock pudding hole grit liar hotel maid produce squeeze return argue turtle know drive eight casino maze host" +USER_2="fuel obscure melt april direct second usual hair leave hobby beef bacon solid drum used law mercy worry fat super must ritual bring faculty" +RELAYER_ACC="old cinnamon boy hurry pipe upset exhibit title copy squirrel grit eye love toy cotton connect inhale cost quarter mistake ahead endless bless license" + +ALICE_GENESIS_COINS=20000token,200000000stake,10000000000uqsr +BOB_GENESIS_COINS=10000token,100000000stake,10000000000uqsr +USER_1_GENESIS_COINS=10000000000stake,10000000000uqsr +USER_2_GENESIS_COINS=10000000000stake,10000000000uqsr +RELAYER_ACC_GENESIS_COINS=10000000uqsr + +# Remove previous setup +rm -rf $HOME_QSR + +$BINARY init $CHAIN_ID --chain-id $CHAIN_ID --home $HOME_QSR + +# Bootstrap the quasar local network with single node + +echo $ALICE | $BINARY keys add alice --keyring-backend test --recover --home $HOME_QSR +echo $BOB | $BINARY keys add bob --keyring-backend test --recover --home $HOME_QSR +echo $USER_1 | $BINARY keys add user1 --keyring-backend test --recover --home $HOME_QSR +echo $USER_2 | $BINARY keys add user2 --keyring-backend test --recover --home $HOME_QSR +echo $RELAYER_ACC | $BINARY keys add relayer_acc --keyring-backend test --recover --home $HOME_QSR + +$BINARY add-genesis-account $($BINARY keys show alice --keyring-backend test -a) $ALICE_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY add-genesis-account $($BINARY keys show bob --keyring-backend test -a) $BOB_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY add-genesis-account $($BINARY keys show user1 --keyring-backend test -a) $USER_1_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY add-genesis-account $($BINARY keys show user2 --keyring-backend test -a) $USER_2_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY add-genesis-account $($BINARY keys show relayer_acc --keyring-backend test -a) $RELAYER_ACC_GENESIS_COINS --home $HOME_QSR --keyring-backend test +$BINARY gentx alice 100000000uqsr --chain-id $CHAIN_ID --keyring-backend test --home $HOME_QSR --keyring-backend test +$BINARY collect-gentxs --home $HOME_QSR + +# Check platform +platform='unknown' +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + platform='linux' +elif [ "$unamestr" = 'Darwin' ]; then + platform='macos' +fi + +if [ $platform = 'linux' ]; then + sed -i 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0uqsr"/g' $HOME_QSR/config/app.toml + sed -i 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +elif [ $platform = 'macos' ]; then + sed -i'.original' -e 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/minimum-gas-prices = ""/minimum-gas-prices = "0uatom"/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i'.original' -e 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +else + echo "only linux and macos platforms are supported, if you are using other platforms you should probably improve this script." + exit 1 +fi + +cp $HOME_QSR/config/genesis.json $HOME_QSR/config/genesis_original.json +cat $HOME_QSR/config/genesis_original.json | + jq '.app_state.crisis.constant_fee.denom="uqsr"' | + jq '.app_state.staking.params.bond_denom="uqsr"' | + jq '.app_state.mint.params.mint_denom="uqsr"' | + jq '.app_state.gov.deposit_params.min_deposit=[{denom:"uqsr",amount:"1"}]' | + jq '.app_state.gov.voting_params.voting_period="600s"' | + jq '.app_state.gov.tally_params={quorum:"0.000000000000000001",threshold:"0.5",veto_threshold:"0.334"}' | + jq '.app_state.qoracle.osmosis_genesis_state.params.authorized_channel="channel-0"' >$HOME_QSR/config/genesis.json + +# Start +$BINARY start --home $HOME_QSR > quasar.log 2>&1 & diff --git a/demos/upgrade-handler/README.md b/demos/upgrade-handler/README.md new file mode 100644 index 000000000..3099bbc0b --- /dev/null +++ b/demos/upgrade-handler/README.md @@ -0,0 +1,29 @@ +# Quasar Upgrade Tests + +## Requirements + +- Read the specific README.md inside the "vx.x.x" related to a specific upgrade. + +## Specifications + +- To create new `.sh tests for future versions, follow the same pattern as shown in the provided test script. Make sure + to update the proposal details, block height for the upgrade, and any additional checks or commands specific to the + new version. + +## Usage + +1. Update the test script with the necessary details for the new software upgrade proposal, such as title, description, + and upgrade height. +2. Run the test script. This will perform the following actions: + - Kill existing quasarnoded processes + - Start the local Quasar network using ./quasar_localnet.sh + - Submit a software upgrade proposal with the specified details + - Sleep for a short duration to allow for proposal submission + - Vote 'yes' on the proposal using the specified account + - Sleep for a short duration to allow for voting + - Wait for the block height to reach the specified upgrade height + - Verify that the upgrade proposal has been successful + +The test script will provide you with the necessary logs and information to verify that each step of the upgrade process +was successful. You can use this test suite to test future software upgrades, ensuring a smooth upgrade process for the +Quasar blockchain. \ No newline at end of file diff --git a/demos/upgrade-handler/quasar_localnet.sh b/demos/upgrade-handler/quasar_localnet.sh new file mode 100755 index 000000000..c95a0a621 --- /dev/null +++ b/demos/upgrade-handler/quasar_localnet.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +## This script helps to create a basic version of the quasar chain genesis file for development purposes. +## However it will need some manual modifications before you start the chain to incorporate the custom fields. + +# Configure variables +BINARY=quasarnoded +HOME_QSR=$HOME/.quasarnode +CHAIN_ID=quasar +MY_TREASURY="edge victory hurry slight dog exit company bike hill erupt shield aspect turkey retreat stairs summer sadness crush absorb draft viable orphan chuckle exhibit" +MY_TREASURY_GENESIS_COINS=20000token,200000000stake,1000000000uqsr + +# Remove previous setup + +rm -rf $HOME_QSR + +$BINARY init $CHAIN_ID --chain-id $CHAIN_ID --home $HOME_QSR + +# Bootstrap the quasar local network with single node + +echo $MY_TREASURY | $BINARY keys add my_treasury --keyring-backend test --recover + +$BINARY add-genesis-account $($BINARY keys show my_treasury --keyring-backend test -a) $MY_TREASURY_GENESIS_COINS + +echo "Creating gentx" +$BINARY gentx my_treasury 100000000uqsr --chain-id $CHAIN_ID --keyring-backend test +echo "Collecting gentx" +$BINARY collect-gentxs + +# Check platform +platform='unknown' +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + platform='linux' +elif [ "$unamestr" = 'Darwin' ]; then + platform='macos' +fi + +if [ $platform = 'linux' ]; then + sed -i 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0uqsr"/g' $HOME_QSR/config/app.toml + sed -i 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +elif [ $platform = 'macos' ]; then + sed -i'.original' -e 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/minimum-gas-prices = ""/minimum-gas-prices = "0uatom"/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i'.original' -e 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +else + echo "only linux and macos platforms are supported, if you are using other platforms you should probably improve this script." + exit 1 +fi + +cp $HOME_QSR/config/genesis.json $HOME_QSR/config/genesis_original.json +cat $HOME_QSR/config/genesis_original.json | + jq '.app_state.crisis.constant_fee.denom="uqsr"' | + jq '.app_state.staking.params.bond_denom="uqsr"' | + jq '.app_state.mint.params.mint_denom="uqsr"' | + jq '.app_state.gov.deposit_params.min_deposit=[{denom:"uqsr",amount:"1"}]' | + jq '.app_state.gov.voting_params.voting_period="60s"' | + jq '.app_state.gov.tally_params={quorum:"0.000000000000000001",threshold:"0.5",veto_threshold:"0.334"}' >$HOME_QSR/config/genesis.json + +# Start +echo "Starting the chain" +$BINARY start --home $HOME_QSR > quasar.log 2>&1 & + +echo "Sleeping 5 seconds to wait quasarnoded to be executed" +sleep 5 diff --git a/demos/upgrade-handler/v0.1.1/README.md b/demos/upgrade-handler/v0.1.1/README.md new file mode 100644 index 000000000..1e9c8a4b3 --- /dev/null +++ b/demos/upgrade-handler/v0.1.1/README.md @@ -0,0 +1,28 @@ +# Quasar Upgrade Tests for v0.1.1 + +## Requirements + +The script should be run by the upgrade branch already containing the new code + +Before the execution: + +- Go to the main branch from another cloned instance of the chain repository +- Execute a "git checkout v0.1.0" +- Execute a "make install" in order to ensure starting from the correct previous mainnet version. +- Go back to the upgrade branch and run the test script + +After the execution: + +- Now that the governance proposal has been success the chain should have been halted. You can check the quasar.log file + expecting to find: UPGRADE "v0.1.1" NEEDED at height: 30: CONSENSUS FAILURE!!! +- You can now "make install" the new version and check that blocks are produced as expected by running "quasarnoded + start". It should start producing blocks from height 31. + +## Usage + +1. Run the test script after setting it as executable: +```bash +cd demos/upgrade-handler/v0.1.1 +chmod +x upgrade_handler_v0_1_1.sh +./upgrade_handler_v0_1_1.sh +``` \ No newline at end of file diff --git a/demos/upgrade-handler/v0.1.1/upgrade_handler_v0_1_1.sh b/demos/upgrade-handler/v0.1.1/upgrade_handler_v0_1_1.sh new file mode 100755 index 000000000..f94e354eb --- /dev/null +++ b/demos/upgrade-handler/v0.1.1/upgrade_handler_v0_1_1.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# TODO: Before running this script go to the main branch, execute a "git checkout v0.1.0" and "make install" the binary in order to start from the mainnet version. +# TODO: Now checkout the upgrade branch and you are able to execute this test script. + +# Kill existing quasarnoded processes +echo ">>> Killing existing quasarnoded processes..." +pkill quasarnoded || true + +# Entry point to run quasar_localnet.sh +../quasar_localnet.sh + +# Define variables +CHAIN_ID=quasar +UPGRADE_HEIGHT=30 + +echo ">>> Sleeping 10 seconds to create some initial blocks" +sleep 10 + +# Submit governance proposal for software-upgrade to v0.1.1 +echo ">>> Submitting proposal for software-upgrade" +quasarnoded tx gov submit-proposal software-upgrade "v0.1.1" --title "Software Upgrade to v0.1.1" --description "This software-upgrade v0.1.1 introduces QVesting module for continuous vesting schedule accounts creation" --upgrade-height $UPGRADE_HEIGHT --deposit 1uqsr --from my_treasury --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 60 seconds after submitting proposal" +sleep 60 + +echo ">>> Voting yes to proposal" +quasarnoded tx gov vote 1 yes --from my_treasury --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5 seconds after voting proposal" +sleep 5 + +# Wait for the block height to reach 100, cosmovisor should handle the upgrade +echo ">>> Waiting for the block height to reach $UPGRADE_HEIGHT" +while true; do + CURRENT_HEIGHT=$(quasarnoded status | jq -r '.SyncInfo.latest_block_height') + echo "Current height: "$CURRENT_HEIGHT + if [ "$CURRENT_HEIGHT" -ge "$UPGRADE_HEIGHT" ]; then + break + fi + sleep 1 +done + +# Check if the upgrade has been successful +quasarnoded query gov proposal 1 --chain-id $CHAIN_ID --output json + +# TODO: Now that the governance proposal has been success the chain should have been halted. You can check the quasar.log file expecting to find: UPGRADE "v0.1.1" NEEDED at height: 30: CONSENSUS FAILURE!!! +# TODO: You can now "make install" the new version and check that blocks are produced as expected by running "quasarnoded start". It should start producing blocks from height 31. diff --git a/demos/upgrade-handler/v1.0.0/README.md b/demos/upgrade-handler/v1.0.0/README.md new file mode 100644 index 000000000..122fc1ddd --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/README.md @@ -0,0 +1,35 @@ +# Quasar Upgrade Tests for v1.0.0 from the current mainnet version v.0.1.1 + +## Requirements + +The script should be run by the upgrade branch already containing the new code + +Before the execution: + +- Go to the main branch from another cloned instance of the chain repository +- Execute a "git checkout v0.1.1" +- Execute a "make install" in order to ensure starting from the correct previous mainnet version. +- Go back to the upgrade branch and run the test script, Before running the test script, open and check the script for +- some pre-requisites and other instructions. + +After the execution: + +- Now that the governance proposal has been success the chain should have been halted. You can check the quasar.log file + expecting to find: UPGRADE "v0.1.1" NEEDED at height: 30: CONSENSUS FAILURE!!! +- You can now "make install" the new version and check that blocks are produced as expected by running "quasarnoded + start". It should start producing blocks from height 31. + +## Usage + +1. Run the test script after setting it as executable: +```bash +cd demos/upgrade-handler/v1.0.0 +chmod +x upgrade_handler_v1_0_0.sh +./upgrade_handler_v1_0_0.sh +``` + +2. After installing the new version binary with v.1.0.0 tag, restart the binary. +```bash +chmod +x restart_v1_0_0_binary.sh +./restart_v1_0_0_binary.sh +``` \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/restart_v1_0_0_binary.sh b/demos/upgrade-handler/v1.0.0/restart_v1_0_0_binary.sh new file mode 100755 index 000000000..4e5325869 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/restart_v1_0_0_binary.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +BINARY=quasarnoded +HOME_QSR=$HOME/.quasarnode +CHAIN_ID=quasar + + +version=`quasarnoded version` +if [ "$version" != "1.0.0" ]; then + echo "You are having incorrect version $version" + echo "Please install the current mainnet version v1.0.0" + exit 1 +fi +pkill quasarnoded || true + +echo "Starting the quasar $version " +$BINARY start --home $HOME_QSR > quasar_new.log 2>&1 & \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/upgrade_handler_v1.0.0.sh b/demos/upgrade-handler/v1.0.0/upgrade_handler_v1.0.0.sh new file mode 100755 index 000000000..3bf065dee --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/upgrade_handler_v1.0.0.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# Pre-requisites +# Before running this script go to the main branch, execute a "git checkout v0.1.1" and "make install" +# the binary in order to start from the mainnet version. + +version=`quasarnoded version` +if [ "$version" != "0.1.1" ]; then + echo "You are having incorrect version $version" + echo "Please install the current mainnet version 0.1.1" + exit 1 +fi + +# Kill existing quasarnoded processes +echo ">>> Killing existing quasarnoded processes..." +pkill quasarnoded || true + +# Entry point to run quasar_localnet.sh +../quasar_localnet.sh + +# Define variables +CHAIN_ID=quasar +UPGRADE_HEIGHT=30 + +echo ">>> Sleeping 10 seconds to create some initial blocks" +sleep 10 +current_block=$(quasarnoded status | jq -r '.SyncInfo.latest_block_height') +echo "current block - $current_block" + +if [ $((current_block)) -lt 5 ]; then + echo "current block - $current_block is less than 5 block, sleep more" + sleep 5 # sleep more +fi + +# Submit governance proposal for software-upgrade to v0.1.1 +echo ">>> Submitting proposal for software-upgrade" +quasarnoded tx gov submit-proposal software-upgrade "v1" --title "Software Upgrade to v1" --description "This software-upgrade v1 introduces qvesting, token factory and authx module" --upgrade-height $UPGRADE_HEIGHT --deposit 100uqsr --from my_treasury --chain-id $CHAIN_ID --keyring-backend test -y + +#sleep 5 + + +echo ">>> Sleeping 60 seconds after submitting proposal" +sleep 60 + +echo ">>> Voting yes to proposal" +quasarnoded tx gov vote 1 yes --from my_treasury --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5 seconds after voting proposal" +sleep 5 + +# Wait for the block height to reach 100, cosmovisor should handle the upgrade +echo ">>> Waiting for the block height to reach $UPGRADE_HEIGHT" +while true; do + CURRENT_HEIGHT=$(quasarnoded status | jq -r '.SyncInfo.latest_block_height') + echo "Current height: "$CURRENT_HEIGHT + if [ "$CURRENT_HEIGHT" -ge "$UPGRADE_HEIGHT" ]; then + break + fi + sleep 1 +done + +echo "Check if the upgrade proposal works." +quasarnoded query gov proposal 1 --chain-id $CHAIN_ID --output json + +## Post chain halt status - +### Check the binary log, and see if "UPGRADE "v1.0.0" NEEDED at height: 30" is available. +### If , yes chain has been halted and not producing blocks. +### `quasarnoded status | jq -r '.SyncInfo.latest_block_height'` command will be returning 30 , and +### will not update the heights. + +### Compile the binary using below commands to get the expected version in place. +### go install -mod=readonly -tags "netgo ledger" -ldflags '-X github.com/cosmos/cosmos-sdk/version.Name=quasar -X github.com/cosmos/cosmos-sdk/version.AppName=quasarnoded -X github.com/cosmos/cosmos-sdk/version.Version=1.0.0 -X github.com/cosmos/cosmos-sdk/version.Commit=00df969376c46d124bb35435aba71160c1def817 -X "github.com/cosmos/cosmos-sdk/version.BuildTags=netgo ledger," -w -s' -trimpath ./cmd/quasarnoded diff --git a/demos/vesting-schedule/README.md b/demos/vesting-schedule/README.md new file mode 100644 index 000000000..9ba0be58e --- /dev/null +++ b/demos/vesting-schedule/README.md @@ -0,0 +1,149 @@ +# Vesting Account Module for Quasar (x/qvesting) + +- [Overview](#overview) +- [Features](#features) +- [Implementation Details](#implementation-details) +- [Testing with standard account](#testing-with-standard-account) +- [Testing with Multi-signature Transactions](#testing-with-multi-signature-transactions) +- [Testing with Ledger Hardware Wallet](#testing-with-ledger-hardware-wallet) + +## Overview + +The `x/qvesting` module provides a way for managing vesting schedules in the Quasar foundation to +use `create-vesting-account` message for investors who had invested but failed to provide address at the time of +genesis. + +The `x/qvesting` module is a custom implementation built on top of the built-in `x/auth/vesting` module to address the +limitations identified in the POC. This custom module extends the functionality of the `x/auth/vesting` module to +provide better flexibility and support for defining the start time for vesting schedules. + +----- + +## Features + +- Ability to define the start time for vesting schedules +- Ability to query `spendable-balances` via query CLI command with pagination +- Compatibility with the built-in `x/auth/vesting` module +- Integration with other modules, such as governance, distribution, and staking + +### Implementation Details + +The `x/qvesting` module is implemented as a wrapper around the `x/auth/vesting` module, with additional functionality +for start_time. It achieves this by using the underlying x/auth KVStore, which allows for the deprecation of the module +once the project upgrades to version 0.47 of the Cosmos SDK, if desired. + +When a transaction is processed involving a vesting account, the module checks the account's vesting schedule and +updates the account's locked tokens accordingly. This allows the vesting module to maintain compatibility with +other modules in the Cosmos SDK while still providing the desired vesting functionality. + +Quasar vesting accounts can interact with other modules in the same way as regular accounts. For example, you can +delegate, undelegate, or redelegate tokens to validators, participate in governance proposals, or claim rewards from the +distribution module. + +----- + +## Query CLI command with pagination (optionals) +```bash +quasarnoded query qvesting spendable-balances (--limit 1) (--count-total) +``` + +## Testing with standard account + +#### Creating a vesting account + +To create a vesting account, you can use the following command: + +```bash +quasarnoded tx qvesting create-vesting-account --from my_treasury --chain-id quasar --keyring-backend test +``` + +#### Querying vesting account information + +To query the vesting account information, you can use the following command: + +```bash +quasarnoded query auth account +``` + +----- + +## Testing with Multi-signature Transactions + +Multi-signature transactions require multiple signatures from different accounts to authorize a transaction. To test the +create-vesting-account transaction with multi-sig accounts, follow these steps: + +Create multiple accounts to act as signers for the multi-sig transaction: +```bash +quasarnoded keys add signer1 --keyring-backend test +quasarnoded keys add signer2 --keyring-backend test +quasarnoded keys add signer3 --keyring-backend test +``` + +Create a multi-sig account using the created signer accounts: +```bash +quasarnoded keys add multisig_account --multisig-threshold 2 --multisig "signer1,signer2,signer3" --keyring-backend test +``` + +Fund the multi-sig account and the signer accounts. +```bash +quasarnoded tx bank send 1000uqsr --from my_treasury --chain-id quasar --keyring-backend test +``` + +Create a create-vesting-account transaction using the multi-sig account as the signer: +```bash +quasarnoded tx qvesting create-vesting-account --from multisig_account --chain-id quasar --keyring-backend test --generate-only > tx.json +``` + +Sign the transaction with each signer: +```bash +quasarnoded tx sign tx.json --from signer1 --multisig --chain-id quasar --keyring-backend test --output-document tx_signed1.json +quasarnoded tx sign tx.json --from signer2 --multisig --chain-id quasar --keyring-backend test --output-document tx_signed2.json +quasarnoded tx sign tx.json --from signer3 --multisig --chain-id quasar --keyring-backend test --output-document tx_signed3.json +``` + +Assemble the signatures and broadcast the transaction: +```bash +quasarnoded tx multisign tx.json multisig_account tx_signed1.json tx_signed2.json tx_signed3.json --chain-id quasar --keyring-backend test > tx_multisig.json +quasarnoded tx broadcast tx_multisig.json --chain-id quasar --keyring-backend test -y +``` + +Verify the custom vesting account has been created successfully: +```bash +quasarnoded query auth account +``` + +## Testing with Ledger Hardware Wallet + +To test the compatibility of the x/qvesting module with Ledger hardware wallets, follow these steps: + +Connect your Ledger device and ensure the Cosmos app is installed and running. + +Retrieve the Ledger account address and adding the key to the keyring: +```bash +quasarnoded keys add ledger_account --ledger +``` + +Fund the Ledger account. + +Create a create-vesting-account transaction using the Ledger account as the signer: +```bash +quasarnoded tx qvesting create-vesting-account --from ledger_account --chain-id quasar --keyring-backend test --generate-only > tx.json +``` + +Sign the transaction with the Ledger device: +```bash +quasarnoded tx sign tx.json --from ledger_account --chain-id quasar --keyring-backend test --output-document tx_signed.json +``` + +Broadcast the signed transaction: +```bash +quasarnoded tx broadcast tx_signed.json --chain-id quasar +``` + +Verify the custom vesting account has been created successfully: +```bash +quasarnoded query auth account +``` + +By performing these tests, you can ensure that the x/qvesting module is compatible with multi-signature +transactions and Ledger hardware wallets, providing a secure and reliable experience for all users. \ No newline at end of file diff --git a/demos/vesting-schedule/quasar_localnet.sh b/demos/vesting-schedule/quasar_localnet.sh new file mode 100755 index 000000000..c95a0a621 --- /dev/null +++ b/demos/vesting-schedule/quasar_localnet.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +## This script helps to create a basic version of the quasar chain genesis file for development purposes. +## However it will need some manual modifications before you start the chain to incorporate the custom fields. + +# Configure variables +BINARY=quasarnoded +HOME_QSR=$HOME/.quasarnode +CHAIN_ID=quasar +MY_TREASURY="edge victory hurry slight dog exit company bike hill erupt shield aspect turkey retreat stairs summer sadness crush absorb draft viable orphan chuckle exhibit" +MY_TREASURY_GENESIS_COINS=20000token,200000000stake,1000000000uqsr + +# Remove previous setup + +rm -rf $HOME_QSR + +$BINARY init $CHAIN_ID --chain-id $CHAIN_ID --home $HOME_QSR + +# Bootstrap the quasar local network with single node + +echo $MY_TREASURY | $BINARY keys add my_treasury --keyring-backend test --recover + +$BINARY add-genesis-account $($BINARY keys show my_treasury --keyring-backend test -a) $MY_TREASURY_GENESIS_COINS + +echo "Creating gentx" +$BINARY gentx my_treasury 100000000uqsr --chain-id $CHAIN_ID --keyring-backend test +echo "Collecting gentx" +$BINARY collect-gentxs + +# Check platform +platform='unknown' +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + platform='linux' +elif [ "$unamestr" = 'Darwin' ]; then + platform='macos' +fi + +if [ $platform = 'linux' ]; then + sed -i 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0uqsr"/g' $HOME_QSR/config/app.toml + sed -i 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +elif [ $platform = 'macos' ]; then + sed -i'.original' -e 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/minimum-gas-prices = ""/minimum-gas-prices = "0uatom"/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i'.original' -e 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +else + echo "only linux and macos platforms are supported, if you are using other platforms you should probably improve this script." + exit 1 +fi + +cp $HOME_QSR/config/genesis.json $HOME_QSR/config/genesis_original.json +cat $HOME_QSR/config/genesis_original.json | + jq '.app_state.crisis.constant_fee.denom="uqsr"' | + jq '.app_state.staking.params.bond_denom="uqsr"' | + jq '.app_state.mint.params.mint_denom="uqsr"' | + jq '.app_state.gov.deposit_params.min_deposit=[{denom:"uqsr",amount:"1"}]' | + jq '.app_state.gov.voting_params.voting_period="60s"' | + jq '.app_state.gov.tally_params={quorum:"0.000000000000000001",threshold:"0.5",veto_threshold:"0.334"}' >$HOME_QSR/config/genesis.json + +# Start +echo "Starting the chain" +$BINARY start --home $HOME_QSR > quasar.log 2>&1 & + +echo "Sleeping 5 seconds to wait quasarnoded to be executed" +sleep 5 diff --git a/demos/vesting-schedule/vesting_schedule_ledger.sh b/demos/vesting-schedule/vesting_schedule_ledger.sh new file mode 100755 index 000000000..bb5bbc8a2 --- /dev/null +++ b/demos/vesting-schedule/vesting_schedule_ledger.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +# Kill existing quasarnoded processes +echo ">>> Killing existing quasarnoded processes..." +pkill quasarnoded || true + +# Entry point to run quasar_localnet.sh +./quasar_localnet.sh + +# Define variables +CHAIN_ID=quasar +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + START_TIME_OK=$(date -d "+10 seconds" +%s) + END_TIME_OK=$(date -d "+60 seconds" +%s) +elif [ "$unamestr" = 'Darwin' ]; then + START_TIME_OK=$(date -v+10S +%s) + END_TIME_OK=$(date -v+60S +%s) +fi + +# Use the my_treasury address created in quasar_localnet.sh +MY_TREASURY=$(quasarnoded keys show my_treasury -a --keyring-backend test) + +echo ">>> Add keys vester_continuous_ok and vester_continuous_ko for further vesting account creation" +# Create vester accounts in the local node for testing +quasarnoded keys add vester_continuous_ok --keyring-backend test +VC_OK_ADDRESS=$(quasarnoded keys show vester_continuous_ok -a --keyring-backend test) + +echo ">>> Create multi-sig account using signer1, signer2, and signer3" +quasarnoded keys add multisig_account --multisig-threshold 2 --multisig "signer1,signer2,signer3" --keyring-backend test +SIGNER1_ADDRESS=$(quasarnoded keys show signer1 -a --ledger) +SIGNER2_ADDRESS=$(quasarnoded keys show signer2 -a --ledger) +SIGNER3_ADDRESS=$(quasarnoded keys show signer3 -a --ledger) +MULTISIG_ADDRESS=$(quasarnoded keys show multisig_account -a --keyring-backend test) +echo "Signer 1: $SIGNER1_ADDRESS" +echo "Signer 2: $SIGNER2_ADDRESS" +echo "Signer 3: $SIGNER3_ADDRESS" +echo "Multisig: $MULTISIG_ADDRESS" + +echo ">>> Fund multisig and signer accounts" +quasarnoded tx bank send $MY_TREASURY $MULTISIG_ADDRESS 1000uqsr --from $MY_TREASURY --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5/35 seconds to elapse 5/35 before querying multisig account" +sleep 5 + +echo ">>> Create create-vesting-account transaction using multisig as the signer" +quasarnoded tx qvesting create-vesting-account $VC_OK_ADDRESS 1000uqsr $START_TIME_OK $END_TIME_OK --from $MULTISIG_ADDRESS --chain-id $CHAIN_ID --keyring-backend test --generate-only > tx.json + +echo ">>> Sign the transaction with each signer" +quasarnoded tx sign tx.json --from signer1 --multisig $MULTISIG_ADDRESS --chain-id $CHAIN_ID --ledger --output-document tx_signed1.json +quasarnoded tx sign tx.json --from signer2 --multisig $MULTISIG_ADDRESS --chain-id $CHAIN_ID --ledger --output-document tx_signed2.json +quasarnoded tx sign tx.json --from signer3 --multisig $MULTISIG_ADDRESS --chain-id $CHAIN_ID --ledger --output-document tx_signed3.json + +echo ">>> Assemble the signatures and broadcast the transaction" +quasarnoded tx multisign tx.json multisig_account tx_signed1.json tx_signed2.json tx_signed3.json --chain-id $CHAIN_ID --keyring-backend test > tx_multisig.json +quasarnoded tx broadcast tx_multisig.json --chain-id $CHAIN_ID -y + +echo ">>> Sleeping 30/35 seconds to elapse 30/35 before sending 500uqsr from Vester to MyTreasury" +sleep 30 + +# Transfer vesting tokens from vester1 to vester2 before the time +echo ">>> Testing OK accounts to be able to send vesting schedule tokens with amount 500uqsr that is half of vesting total" +quasarnoded tx bank send $VC_OK_ADDRESS $MY_TREASURY 500uqsr --from vester_continuous_ok --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5 seconds after sending bank tx from OK case" +sleep 5 + +echo ">>> Testing again OK account to NOT be able to send vesting schedule tokens with amount 250uqsr that is a quarter of vesting total and should be locked already" +quasarnoded tx bank send $VC_OK_ADDRESS $MY_TREASURY 250uqsr --from vester_continuous_ok --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5 more seconds..." +sleep 5 + +echo ">>> Expecting OK balances equals to 500uqsr" +quasarnoded query bank balances $VC_OK_ADDRESS + +# Remove all the generated .json filed related to transaction signatures +rm -rf tx.json tx_signed1.json tx_signed2.json tx_signed3.json tx_multisig.json diff --git a/demos/vesting-schedule/vesting_schedule_multisig.sh b/demos/vesting-schedule/vesting_schedule_multisig.sh new file mode 100755 index 000000000..a95c6cafd --- /dev/null +++ b/demos/vesting-schedule/vesting_schedule_multisig.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# Kill existing quasarnoded processes +echo ">>> Killing existing quasarnoded processes..." +pkill quasarnoded || true + +# Entry point to run quasar_localnet.sh +./quasar_localnet.sh + +# Define variables +CHAIN_ID=quasar +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + START_TIME_OK=$(date -d "+10 seconds" +%s) + END_TIME_OK=$(date -d "+60 seconds" +%s) +elif [ "$unamestr" = 'Darwin' ]; then + START_TIME_OK=$(date -v+10S +%s) + END_TIME_OK=$(date -v+60S +%s) +fi + +# Use the my_treasury address created in quasar_localnet.sh +MY_TREASURY=$(quasarnoded keys show my_treasury -a --keyring-backend test) + +echo ">>> Add keys vester_continuous_ok and vester_continuous_ko for further vesting account creation" +# Create vester accounts in the local node for testing +quasarnoded keys add vester_continuous_ok --keyring-backend test +VC_OK_ADDRESS=$(quasarnoded keys show vester_continuous_ok -a --keyring-backend test) + +echo ">>> Create signer1, signer2, and signer3 keys" +quasarnoded keys add signer1 --keyring-backend test +quasarnoded keys add signer2 --keyring-backend test +quasarnoded keys add signer3 --keyring-backend test +echo ">>> Create multi-sig account using signer1, signer2, and signer3" +quasarnoded keys add multisig_account --multisig-threshold 2 --multisig "signer1,signer2,signer3" --keyring-backend test +SIGNER1_ADDRESS=$(quasarnoded keys show signer1 -a --keyring-backend test) +SIGNER2_ADDRESS=$(quasarnoded keys show signer2 -a --keyring-backend test) +SIGNER3_ADDRESS=$(quasarnoded keys show signer3 -a --keyring-backend test) +MULTISIG_ADDRESS=$(quasarnoded keys show multisig_account -a --keyring-backend test) +echo "Signer 1: $SIGNER1_ADDRESS" +echo "Signer 2: $SIGNER2_ADDRESS" +echo "Signer 3: $SIGNER3_ADDRESS" +echo "Multisig: $MULTISIG_ADDRESS" + + +echo ">>> Fund multisig and signer accounts" +quasarnoded tx bank send $MY_TREASURY $MULTISIG_ADDRESS 1000uqsr --from $MY_TREASURY --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5/35 seconds to elapse 5/35 before querying multisig account" +sleep 5 + +echo ">>> Create create-vesting-account transaction using multisig as the signer" +quasarnoded tx qvesting create-vesting-account $VC_OK_ADDRESS 1000uqsr $START_TIME_OK $END_TIME_OK --from $MULTISIG_ADDRESS --chain-id $CHAIN_ID --keyring-backend test --generate-only > tx.json + +echo ">>> Sign the transaction with each signer" +quasarnoded tx sign tx.json --from signer1 --multisig $MULTISIG_ADDRESS --chain-id $CHAIN_ID --keyring-backend test --output-document tx_signed1.json +quasarnoded tx sign tx.json --from signer2 --multisig $MULTISIG_ADDRESS --chain-id $CHAIN_ID --keyring-backend test --output-document tx_signed2.json +quasarnoded tx sign tx.json --from signer3 --multisig $MULTISIG_ADDRESS --chain-id $CHAIN_ID --keyring-backend test --output-document tx_signed3.json + +echo ">>> Assemble the signatures and broadcast the transaction" +quasarnoded tx multisign tx.json multisig_account tx_signed1.json tx_signed2.json tx_signed3.json --chain-id $CHAIN_ID --keyring-backend test > tx_multisig.json +quasarnoded tx broadcast tx_multisig.json --chain-id $CHAIN_ID -y + +echo ">>> Sleeping 30/35 seconds to elapse 35/35 before sending 500uqsr from Vester to MyTreasury" +sleep 30 + +# Transfer vesting tokens from vester1 to vester2 before the time +echo ">>> Testing OK accounts to be able to send vesting schedule tokens with amount 500uqsr that is half of vesting total" +quasarnoded tx bank send $VC_OK_ADDRESS $MY_TREASURY 500uqsr --from vester_continuous_ok --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5 seconds after sending bank tx from OK case" +sleep 5 + +echo ">>> Testing again OK account to NOT be able to send vesting schedule tokens with amount 250uqsr that is a quarter of vesting total and should be locked already" +quasarnoded tx bank send $VC_OK_ADDRESS $MY_TREASURY 250uqsr --from vester_continuous_ok --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5 more seconds..." +sleep 5 + +echo ">>> Expecting OK balances equals to 500uqsr" +quasarnoded query bank balances $VC_OK_ADDRESS + +# Remove all the generated .json filed related to transaction signatures +rm -rf tx.json tx_signed1.json tx_signed2.json tx_signed3.json tx_multisig.json diff --git a/demos/vesting-schedule/vesting_schedule_standard.sh b/demos/vesting-schedule/vesting_schedule_standard.sh new file mode 100755 index 000000000..d147b6ef0 --- /dev/null +++ b/demos/vesting-schedule/vesting_schedule_standard.sh @@ -0,0 +1,76 @@ +#!/bin/bash +set -o xtrace +# Kill existing quasarnoded processes +echo ">>> Killing existing quasarnoded processes..." +pkill quasarnoded || true + +# Entry point to run quasar_localnet.sh +./quasar_localnet.sh + +# Define variables +CHAIN_ID=quasar +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + START_TIME_OK=$(date -d "+5 seconds" +%s) + END_TIME_OK=$(date -d "+60 seconds" +%s) + START_TIME_KO=$(date -d "+900 seconds" +%s) + END_TIME_KO=$(date -d "+1800 seconds" +%s) +elif [ "$unamestr" = 'Darwin' ]; then + START_TIME_OK=$(date -v+5S +%s) + END_TIME_OK=$(date -v+60S +%s) + START_TIME_KO=$(date -v+900S +%s) + END_TIME_KO=$(date -v+1800S +%s) +fi + +# Use the my_treasury address created in quasar_localnet.sh +MY_TREASURY=$(quasarnoded keys show my_treasury -a --keyring-backend test) + +echo ">>> Add keys vester_continuous_ok and vester_continuous_ko for further vesting account creation" +# Create vester accounts in the local node for testing +quasarnoded keys add vester_continuous_ok --keyring-backend test +quasarnoded keys add vester_continuous_ko --keyring-backend test +VC_OK_ADDRESS=$(quasarnoded keys show vester_continuous_ok -a --keyring-backend test) +VC_KO_ADDRESS=$(quasarnoded keys show vester_continuous_ko -a --keyring-backend test) + +echo ">>> Creating OK accounts" +# Create vesting account executing as my_treasury for vester_continuous_ok +quasarnoded tx qvesting create-vesting-account $VC_OK_ADDRESS 1000uqsr $START_TIME_OK $END_TIME_OK --from my_treasury --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5/35 seconds to elapse 5/35 before querying accounts to check vesting balances and start times" +sleep 5 + +echo ">>> Creating KO accounts" +# Create vesting account executing as my_treasury for vester_continuous_ok +quasarnoded tx qvesting create-vesting-account $VC_KO_ADDRESS 1000uqsr $START_TIME_KO $END_TIME_KO --from my_treasury --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5/35 seconds to elapse 10/35 before querying accounts to check vesting balances and start times" +sleep 5 + +# Check that the vesting account has been created successfully +echo ">>> Query accounts" +quasarnoded query auth account $VC_OK_ADDRESS +quasarnoded query auth account $VC_KO_ADDRESS + +echo ">>> Sleeping 25/35 seconds to elapse 35/35 seconds" +sleep 25 + +# Transfer vesting tokens from vester1 to vester2 before the time +echo ">>> Testing OK accounts to be able to send vesting schedule tokens with amount 500uqsr that is half of vesting total" +quasarnoded tx bank send $VC_OK_ADDRESS $MY_TREASURY 500uqsr --from vester_continuous_ok --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5 seconds after sending bank tx from OK case" +#sleep 5 + +echo ">>> Testing again OK account to NOT be able to send vesting schedule tokens with amount 250uqsr that is a quarter of vesting total and should be locked already" +quasarnoded tx bank send $VC_OK_ADDRESS $MY_TREASURY 250uqsr --from vester_continuous_ok --chain-id $CHAIN_ID --keyring-backend test -y +echo ">>> Testing KO accounts to be NOT able to send vesting schedule tokens, even 1 should fail as vesting is in the future" +quasarnoded tx bank send $VC_KO_ADDRESS $MY_TREASURY 1uqsr --from vester_continuous_ko --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5 seconds..." +sleep 5 + +echo ">>> Expecting OK balances equals to 500uqsr" +quasarnoded query bank balances $VC_OK_ADDRESS +echo ">>> Expecting balances equals to 1000uqsr" +quasarnoded query bank balances $VC_KO_ADDRESS + diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index 216345f65..6ed2504d1 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -3755,6 +3755,161 @@ paths: } tags: - Query + /quasarlabs/quasarnode/qvesting/params: + get: + summary: Parameters queries the parameters of the module. + operationId: QVestingParams + responses: + '200': + description: A successful response. + content: + "*/*": + schema: + type: object + properties: + params: + description: params holds all the parameters of this module. + type: object + description: >- + QueryParamsResponse is response type for the Query/Params RPC + method. + default: + description: An unexpected error response. + content: + "*/*": + schema: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + '@type': + type: string + additionalProperties: {} + tags: + - Query + /quasarlabs/quasarnode/qvesting/spendable_balances/{address}: + get: + summary: SpendableBalances queries the spenable balance of all coins for a single account. + operationId: SpendableBalances + responses: + '200': + description: A successful response. + default: + description: An unexpected error response. + parameters: + - name: address + description: address is the address to query spendable balances for. + in: path + required: true + schema: + type: string + - name: pagination.key + description: key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set. + in: query + required: false + schema: + type: string + format: byte + - name: pagination.offset + description: offset is a numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.limit + description: limit is the total number of results to be returned in the result page. If left empty it will default to a value to be set by each app. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.count_total + description: count_total is set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. count_total is only respected when offset is used. It is ignored when key is set. + in: query + required: false + schema: + type: boolean + - name: pagination.reverse + description: reverse is set to true if results are to be returned in the descending order. + in: query + required: false + schema: + type: boolean + tags: + - Query + /quasarlabs/quasarnode/qvesting/accounts: + get: + summary: VestingAccounts returns all the existing vesting accounts + operationId: VestingAccounts + responses: + '200': + description: A successful response. + default: + description: An unexpected error response. + parameters: + - name: pagination.key + description: key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set. + in: query + required: false + schema: + type: string + format: byte + - name: pagination.offset + description: offset is a numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.limit + description: limit is the total number of results to be returned in the result page. If left empty it will default to a value to be set by each app. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.count_total + description: count_total is set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. count_total is only respected when offset is used. It is ignored when key is set. + in: query + required: false + schema: + type: boolean + - name: pagination.reverse + description: reverse is set to true if results are to be returned in the descending order. + in: query + required: false + schema: + type: boolean + tags: + - Query + /quasarlabs/quasarnode/qvesting/locked_supply/{denom}: + get: + summary: VestingLockedSupply returns the locked supply for a given denom + operationId: VestingLockedSupply + responses: + '200': + description: A successful response. + default: + description: An unexpected error response. + parameters: + - name: denom + description: denom is the denom to query locked supply for. + in: path + required: true + schema: + type: string + tags: + - Query + components: schemas: google.protobuf.Any: @@ -8111,3 +8266,42 @@ components: updated_at_height: type: string format: int64 + quasarlabs.quasarnode.qvesting.MsgCreateVestingAccountResponse: + type: object + quasarlabs.quasarnode.qvesting.Params: + type: object + description: Params defines the parameters for the module. + quasarlabs.quasarnode.qvesting.QueryParamsResponse: + type: object + properties: + params: + description: params holds all the parameters of this module. + type: object + description: QueryParamsResponse is response type for the Query/Params RPC method. + quasarlabs.quasarnode.qvesting.QuerySpendableBalancesResponse: + type: object + properties: + balances: + type: array + description: balances is the spendable balances of all the coins. + pagination: + description: pagination defines the pagination in the response. + description: QuerySpendableBalancesResponse defines the gRPC response structure for querying\nan account's spendable balances. + quasarlabs.quasarnode.qvesting.QueryVestingAccountsResponse: + type: object + properties: + accounts: + type: array + title: accounts are the existing vesting accounts + pagination: + description: pagination defines the pagination in the response. + description: QueryVestingAccountsResponse is the response type for the Query/Accounts RPC method. + quasarlabs.quasarnode.qvesting.QueryVestingLockedSupplyResponse: + type: object + properties: + denom: + type: string + amount: + type: string + description: QueryVestingLockedSupplyResponse is the response type for the Query/AccountsLockedSupply RPC method. + diff --git a/go.mod b/go.mod index a34a97e80..c21116427 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,10 @@ module github.com/quasarlabs/quasarnode -go 1.18 +go 1.20 require ( github.com/CosmWasm/wasmd v0.31.0 - github.com/cosmos/cosmos-sdk v0.45.14 + github.com/cosmos/cosmos-sdk v0.45.16 github.com/cosmos/ibc-go/v4 v4.3.0 github.com/gogo/protobuf v1.3.3 github.com/golang/mock v1.6.0 @@ -19,7 +19,7 @@ require ( github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.8.2 - github.com/tendermint/tendermint v0.34.26 + github.com/tendermint/tendermint v0.34.27 github.com/tendermint/tm-db v0.6.7 google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa google.golang.org/grpc v1.53.0 @@ -29,7 +29,7 @@ require ( ) require ( - github.com/CosmWasm/wasmvm v1.2.1 + github.com/CosmWasm/wasmvm v1.2.3 github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/gogoproto v1.4.6 github.com/strangelove-ventures/async-icq/v4 v4.0.0-rc0 @@ -40,13 +40,14 @@ require ( cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.3 // indirect github.com/Abirdcfly/dupword v0.0.7 // indirect - github.com/DataDog/zstd v1.4.5 // indirect + github.com/DataDog/zstd v1.5.0 // indirect github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 // indirect github.com/cockroachdb/redact v1.1.3 // indirect + github.com/cometbft/cometbft-db v0.7.0 // indirect github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect @@ -62,6 +63,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect + github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tidwall/btree v1.5.0 // indirect github.com/timonwong/loggercheck v0.9.3 // indirect github.com/zondax/ledger-go v0.14.1 // indirect @@ -84,7 +86,7 @@ require ( github.com/Workiva/go-datastructures v1.0.53 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect - github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-metrics v0.4.1 github.com/ashanbrown/forbidigo v1.3.0 // indirect github.com/ashanbrown/makezero v1.1.1 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -94,13 +96,12 @@ require ( github.com/bombsimon/wsl/v3 v3.3.0 // indirect github.com/breml/bidichk v0.2.3 // indirect github.com/breml/errchkjson v0.3.0 // indirect - github.com/btcsuite/btcd v0.22.2 // indirect github.com/butuzov/ireturn v0.1.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/charithe/durationcheck v0.0.9 // indirect github.com/chavacava/garif v0.0.0-20220630083739-93517212f375 // indirect - github.com/coinbase/rosetta-sdk-go v0.7.0 // indirect + github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect github.com/confio/ics23/go v0.9.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect @@ -274,7 +275,7 @@ require ( golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 // indirect golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 // indirect golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.6.0 // indirect + golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/term v0.5.0 // indirect @@ -297,7 +298,8 @@ replace ( github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 // use informal system fork of tendermint // See https://twitter.com/informalinc/status/1613580954383040512 - github.com/tendermint/tendermint => github.com/informalsystems/tendermint v0.34.26 + // github.com/tendermint/tendermint => github.com/informalsystems/tendermint v0.34.26 + github.com/tendermint/tendermint => github.com/cometbft/cometbft v0.34.27 // To fix https://github.com/cosmos/cosmos-sdk/issues/8426 google.golang.org/grpc => google.golang.org/grpc v1.33.2 ) diff --git a/go.sum b/go.sum index dfd4877a5..5148d78d3 100644 --- a/go.sum +++ b/go.sum @@ -2,12 +2,14 @@ 4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= @@ -24,6 +26,7 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -36,6 +39,7 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= cosmossdk.io/api v0.2.6 h1:AoNwaLLapcLsphhMK6+o0kZl+D6MMUaHVqSdwinASGU= cosmossdk.io/api v0.2.6/go.mod h1:u/d+GAxil0nWpl1XnQL8nkziQDIWuBDhv8VnDm/s6dI= cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI= @@ -45,6 +49,8 @@ cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3s dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +git.sr.ht/~sircmpwn/getopt v0.0.0-20191230200459-23622cc906b3/go.mod h1:wMEGFFFNuPos7vHmWXfszqImLppbc0wEhh6JBfJIUgw= +git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9/go.mod h1:BVJwbDfVjCjoFiKrhkei6NdGcZYpkDkdyCdg1ukytRA= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= @@ -56,20 +62,10 @@ github.com/Antonboom/errname v0.1.7 h1:mBBDKvEYwPl4WFFNwec1CZO096G6vzK9vvDQzAwka github.com/Antonboom/errname v0.1.7/go.mod h1:g0ONh16msHIPgJSGsecu1G/dcF2hlYR/0SddnIAGavU= github.com/Antonboom/nilnil v0.1.1 h1:PHhrh5ANKFWRBh7TdYmyyq2gyT2lotnvFvvFbylF81Q= github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= -github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -82,12 +78,13 @@ github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mo github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/CosmWasm/wasmd v0.31.0 h1:xACf6A/SkCeGWQWrKGsR4X9PQb5G4XYuNfnrl+HQ1mE= github.com/CosmWasm/wasmd v0.31.0/go.mod h1:VcyDGk/ISVlMUeW+1GGL0zdHWBS2FPwLEV2qZ86l7l8= -github.com/CosmWasm/wasmvm v1.2.1 h1:si0tRsRDdUShV0k51Wn6zRKlmj3/WWP9Yr4cLmDTf+8= -github.com/CosmWasm/wasmvm v1.2.1/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8J7KFtkc= +github.com/CosmWasm/wasmvm v1.2.3 h1:OKYlobwmVGbl0eSn0mXoAAjE5hIuXnQCLPjbNd91sVY= +github.com/CosmWasm/wasmvm v1.2.3/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8J7KFtkc= +github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.0 h1:+K/VEwIAaPcHiMtQvpLD4lqW7f0Gk3xdYZmI1hD+CXo= +github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 h1:+r1rSv4gvYn0wmRjC8X7IAzX8QezqtFV9m0MUHFJgts= @@ -109,7 +106,7 @@ github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqR github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= @@ -131,10 +128,11 @@ github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cv github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -147,9 +145,17 @@ github.com/ashanbrown/forbidigo v1.3.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBF github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= +github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= +github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8= +github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4= +github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= +github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= +github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -163,26 +169,31 @@ github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7 github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= +github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM= github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= github.com/breml/bidichk v0.2.3 h1:qe6ggxpTfA8E75hdjWPZ581sY3a2lnl0IRxLQFelECI= github.com/breml/bidichk v0.2.3/go.mod h1:8u2C6DnAy0g2cEq+k/A2+tr9O1s+vHGxWn0LTc70T2A= github.com/breml/errchkjson v0.3.0 h1:YdDqhfqMT+I1vIxPSas44P+9Z9HzJwCeAzjB8PxP1xw= github.com/breml/errchkjson v0.3.0/go.mod h1:9Cogkyv9gcT8HREpzi3TiqBxCqDzo8awa92zSDFcofU= -github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= +github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs= +github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= github.com/btcsuite/btcd v0.22.2 h1:vBZ+lGGd1XubpOWO67ITJpAEsICWhA0YzqkcpkgNBfo= -github.com/btcsuite/btcd v0.22.2/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= @@ -192,6 +203,8 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY= github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -212,7 +225,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= -github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= +github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -234,8 +247,17 @@ github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= -github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg= -github.com/coinbase/rosetta-sdk-go v0.7.0/go.mod h1:7nD3oBPIiHqhRprqvMgPoGxe/nyq3yftRmpsy29coWE= +github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= +github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA= +github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= +github.com/cometbft/cometbft v0.34.27 h1:ri6BvmwjWR0gurYjywcBqRe4bbwc3QVs9KRcCzgh/J0= +github.com/cometbft/cometbft v0.34.27/go.mod h1:BcCbhKv7ieM0KEddnYXvQZR+pZykTKReJJYf7YC7qhw= +github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= +github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= +github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= +github.com/consensys/bavard v0.1.8-0.20210915155054-088da2f7f54a/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= +github.com/consensys/gnark-crypto v0.5.3/go.mod h1:hOdPlWQV1gDLp7faZVeg8Y0iEPFaOUnCc4XeCCk96p0= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -249,8 +271,8 @@ github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32 h1:zlCp9n3uwQieEL github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32/go.mod h1:kwMlEC4wWvB48zAShGKVqboJL6w4zCLesaNQ3YLU2BQ= github.com/cosmos/cosmos-proto v1.0.0-beta.2 h1:X3OKvWgK9Gsejo0F1qs5l8Qn6xJV/AzgIWR2wZ8Nua8= github.com/cosmos/cosmos-proto v1.0.0-beta.2/go.mod h1:+XRCLJ14pr5HFEHIUcn51IKXD1Fy3rkEQqt4WqmN4V0= -github.com/cosmos/cosmos-sdk v0.45.14 h1:l6yid1Lft5dd8ymKO36qJf1phsE0shJLNkZQYTwjxOg= -github.com/cosmos/cosmos-sdk v0.45.14/go.mod h1:bF1fyVbRDvZ922GMByg9opQT26sQwabwYqaYIchwdyw= +github.com/cosmos/cosmos-sdk v0.45.16 h1:5ba/Bh5/LE55IwHQuCU4fiG4eXeDKtSWzehXRpaKDcw= +github.com/cosmos/cosmos-sdk v0.45.16/go.mod h1:bScuNwWAP0TZJpUf+SHXRU3xGoUPp+X9nAzfeIXts40= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 h1:iKclrn3YEOwk4jQHT2ulgzuXyxmzmPczUalMwW4XH9k= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpFP3wWDPgdHPargtyw30= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= @@ -279,26 +301,29 @@ github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbd github.com/cucumber/common/messages/go/v17 v17.1.1 h1:RNqopvIFyLWnKv0LfATh34SWBhXeoFTJnSrgm9cT/Ts= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= +github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/daixiang0/gci v0.8.1 h1:T4xpSC+hmsi4CSyuYfIJdMZAr9o7xZmHpQVygMghGZ4= github.com/daixiang0/gci v0.8.1/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= +github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= @@ -306,28 +331,31 @@ github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70d github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= 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/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac h1:opbrjaN/L8gg6Xh5D04Tem+8xVcz6ajZlGCs49mQgyg= github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= -github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -335,16 +363,14 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= +github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= @@ -354,7 +380,7 @@ github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8S github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= -github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -369,6 +395,8 @@ github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= github.com/getsentry/sentry-go v0.17.0 h1:UustVWnOoDFHBS7IJUB2QK/nB5pap748ZEp0swnQJak= github.com/getsentry/sentry-go v0.17.0/go.mod h1:B82dxtBvxG0KaPD8/hfSV+VcHD+Lg/xUS4JuQn1P4cM= @@ -380,7 +408,10 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-critic/go-critic v0.6.5 h1:fDaR/5GWURljXwF8Eh31T2GZNz9X4jeboS912mWF8Uo= github.com/go-critic/go-critic v0.6.5/go.mod h1:ezfP/Lh7MA6dBNn4c6ab5ALv3sKnZVLx37tr00uuaOY= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -404,6 +435,8 @@ github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNV github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= @@ -411,8 +444,9 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= -github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= @@ -449,6 +483,7 @@ github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= @@ -456,7 +491,9 @@ github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q8 github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= @@ -491,8 +528,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -506,6 +541,7 @@ github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 h1:amWTbTGqOZ71ruzr github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs= github.com/golangci/golangci-lint v1.50.1 h1:C829clMcZXEORakZlwpk7M4iDw2XiwxxKaG504SZ9zY= github.com/golangci/golangci-lint v1.50.1/go.mod h1:AQjHBopYS//oB8xs0y0M/dtxdKHkdhl0RvmjUct0/4w= +github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= @@ -521,6 +557,7 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -559,6 +596,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -574,8 +612,8 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= @@ -593,7 +631,7 @@ github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3 github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= -github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= @@ -615,6 +653,7 @@ github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyN github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -638,7 +677,6 @@ github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -651,10 +689,11 @@ github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 h1:aSV github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3/go.mod h1:5PC6ZNPde8bBqU/ewGZig35+UIZtw9Ytxez8/q5ZyFE= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= @@ -666,17 +705,25 @@ github.com/improbable-eng/grpc-web v0.14.1/go.mod h1:zEjGHa8DAlkoOXmswrNvhUGEYQA github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= +github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= +github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/informalsystems/tendermint v0.34.26 h1:89XvVexAy62geGWxmDmdmmJvfindx+Su2oTuwfSWMeU= -github.com/informalsystems/tendermint v0.34.26/go.mod h1:q3uAZ/t5+MblQhFuHSd4flqaLDx7iUtWpwWbwvHAFhs= +github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= +github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= +github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= +github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= +github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= -github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -688,6 +735,8 @@ github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+D github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= @@ -704,18 +753,19 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= -github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= @@ -733,6 +783,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkHAIKE/contextcheck v1.1.3 h1:l4pNvrb8JSwRd51ojtcOxOeHJzHek+MtOyXbaR0uvmw= github.com/kkHAIKE/contextcheck v1.1.3/go.mod h1:PG/cwd6c0705/LM0KTr1acO2gORUxkSVWyLJOFW5qoo= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -741,13 +792,16 @@ github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= +github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -763,12 +817,14 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M= github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA= github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= github.com/ldez/tagliatelle v0.3.1 h1:3BqVVlReVUZwafJUwQ+oxbx2BEX2vUG4Yu/NOfMiKiM= github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leonklingele/grouper v1.1.0 h1:tC2y/ygPbMFSBOs3DcyaEMKnnwH7eYKzohOtRrf0SAg= @@ -788,6 +844,8 @@ github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xq github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= github.com/maratori/testpackage v1.1.0 h1:GJY4wlzQhuBusMF1oahQCBtUV/AQ/k69IZ68vxaac2Q= @@ -796,20 +854,18 @@ github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7 github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= @@ -819,11 +875,12 @@ github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peK github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= @@ -851,9 +908,11 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -861,9 +920,11 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/moricho/tparallel v0.2.1 h1:95FytivzT6rYzdJLdtfn6m1bfFJylOJK41+lgv/EHf4= github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -885,7 +946,7 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= -github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= +github.com/neilotoole/errgroup v0.1.6/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/exhaustive v0.8.3 h1:pw5O09vwg8ZaditDp/nQRqVnrMczSJDxRDJMowvhsrM= github.com/nishanths/exhaustive v0.8.3/go.mod h1:qj+zJJUgJ76tR92+25+03oYUhzF4R7/2Wk7fGTfCHmg= @@ -898,8 +959,6 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -924,6 +983,7 @@ github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= @@ -940,7 +1000,7 @@ github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIw github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= @@ -948,11 +1008,13 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= +github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -965,6 +1027,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polyfloyd/go-errorlint v1.0.5 h1:AHB5JRCjlmelh9RrLxT9sgzpalIwwq4hqE8EkwIwKdY= @@ -991,6 +1054,7 @@ github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3d github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= @@ -1009,7 +1073,7 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= github.com/quasilyte/go-ruleguard v0.3.18 h1:sd+abO1PEI9fkYennwzHn9kl3nqP6M5vE7FiOzZ+5CE= github.com/quasilyte/go-ruleguard v0.3.18/go.mod h1:lOIzcYlgxrQ2sGJ735EHXmf/e9MJ516j16K/Ifcttvs= @@ -1033,6 +1097,7 @@ github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNw github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGnWA97M= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= +github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -1044,11 +1109,9 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= @@ -1076,11 +1139,13 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/securego/gosec/v2 v2.13.1 h1:7mU32qn2dyC81MH9L2kefnQyRMUarfDER3iQyMHcjYM= github.com/securego/gosec/v2 v2.13.1/go.mod h1:EO1sImBMBWFjOTFzMWfTRrZW6M15gm60ljzrmy/wtHo= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= +github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= +github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= -github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -1132,8 +1197,6 @@ github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRk github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= -github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= -github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/strangelove-ventures/async-icq/v4 v4.0.0-rc0 h1:foE/5O2/XiqGsdTKx3R0BTfKgW9KnUYyQLZt0WFSesE= github.com/strangelove-ventures/async-icq/v4 v4.0.0-rc0/go.mod h1:thzXHoaK1MgPDCjN7Rp9A/VcHA4cmjQpKCtVNt2O2xk= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1145,6 +1208,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1157,11 +1221,12 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tdakkota/asciicheck v0.1.1 h1:PKzG7JUTUmVspQTDqtkX9eSiLGossXTybutHwTXuO0A= github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8= @@ -1174,15 +1239,19 @@ github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= github.com/tidwall/btree v1.5.0 h1:iV0yVY/frd7r6qGBXfEYs7DH0gTDgrKTrDjS7xt/IyQ= github.com/tidwall/btree v1.5.0/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE= -github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= -github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDHS9/4U9yQo1UcPQM0kOMJHn29EoH/Ro= github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/timonwong/loggercheck v0.9.3 h1:ecACo9fNiHxX4/Bc02rW2+kaJIAMAes7qJ7JKxt0EZI= github.com/timonwong/loggercheck v0.9.3/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw= +github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= +github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= +github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tomarrell/wrapcheck/v2 v2.7.0 h1:J/F8DbSKJC83bAvC6FoZaRjZiZ/iKoueSdrEkmGeacA= github.com/tomarrell/wrapcheck/v2 v2.7.0/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg= @@ -1204,6 +1273,7 @@ github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqz github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/uudashr/gocognit v1.0.6 h1:2Cgi6MweCsdB6kpcVQp7EW4U23iBFQWfTXiWlyp842Y= github.com/uudashr/gocognit v1.0.6/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY= @@ -1212,13 +1282,14 @@ github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBn github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI= -github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= @@ -1266,6 +1337,7 @@ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+ go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= @@ -1288,8 +1360,10 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= @@ -1300,7 +1374,6 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= @@ -1331,12 +1404,10 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -1350,7 +1421,6 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1387,21 +1457,25 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 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= @@ -1458,6 +1532,7 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1477,9 +1552,8 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1489,14 +1563,18 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1514,6 +1592,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= @@ -1534,6 +1613,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1570,7 +1650,7 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1632,8 +1712,11 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= @@ -1671,6 +1754,7 @@ google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -1678,6 +1762,7 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= @@ -1732,6 +1817,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1774,6 +1860,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA= honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM= @@ -1791,5 +1878,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/proto/qvesting/genesis.proto b/proto/qvesting/genesis.proto new file mode 100644 index 000000000..32082eb94 --- /dev/null +++ b/proto/qvesting/genesis.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; +package quasarlabs.quasarnode.qvesting; + +import "gogoproto/gogo.proto"; +import "qvesting/params.proto"; +// this line is used by starport scaffolding # genesis/proto/import + +option go_package = "github.com/quasarlabs/quasarnode/x/qvesting/types"; + +// GenesisState defines the qvesting module's genesis state. +message GenesisState { + Params params = 1 [(gogoproto.nullable) = false]; + // this line is used by starport scaffolding # genesis/proto/state +} diff --git a/proto/qvesting/params.proto b/proto/qvesting/params.proto new file mode 100644 index 000000000..3383198f2 --- /dev/null +++ b/proto/qvesting/params.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package quasarlabs.quasarnode.qvesting; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/quasarlabs/quasarnode/x/qvesting/types"; + +// Params defines the parameters for the module. +message Params { + option (gogoproto.goproto_stringer) = false; + +} diff --git a/proto/qvesting/query.proto b/proto/qvesting/query.proto new file mode 100644 index 000000000..5efce5bd2 --- /dev/null +++ b/proto/qvesting/query.proto @@ -0,0 +1,92 @@ +syntax = "proto3"; +package quasarlabs.quasarnode.qvesting; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "qvesting/params.proto"; +import "google/protobuf/any.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos_proto/cosmos.proto"; + +option go_package = "github.com/quasarlabs/quasarnode/x/qvesting/types"; + +// Query defines the gRPC querier service. +service Query { + // Parameters queries the parameters of the module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/quasarlabs/quasarnode/qvesting/params"; + } + // SpendableBalances queries the spenable balance of all coins for a single account. + rpc SpendableBalances(QuerySpendableBalancesRequest) returns (QuerySpendableBalancesResponse) { + option (google.api.http).get = "/quasarlabs/quasarnode/qvesting/spendable_balances/{address}"; + } + // VestingAccounts returns all the existing vesting accounts + rpc VestingAccounts(QueryVestingAccountsRequest) returns (QueryVestingAccountsResponse) { + option (google.api.http).get = "/quasarlabs/quasarnode/qvesting/accounts"; + } + // VestingAccounts returns all the existing vesting accounts + rpc VestingLockedSupply(QueryVestingLockedSupplyRequest) returns (QueryVestingLockedSupplyResponse) { + option (google.api.http).get = "/quasarlabs/quasarnode/qvesting/locked_supply/{denom}"; + } +} + +// QueryParamsRequest is request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is response type for the Query/Params RPC method. +message QueryParamsResponse { + // params holds all the parameters of this module. + Params params = 1 [(gogoproto.nullable) = false]; +} + +// QuerySpendableBalancesRequest defines the gRPC request structure for querying +// an account's spendable balances. +message QuerySpendableBalancesRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // address is the address to query spendable balances for. + string address = 1; + + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QuerySpendableBalancesResponse defines the gRPC response structure for querying +// an account's spendable balances. +message QuerySpendableBalancesResponse { + // balances is the spendable balances of all the coins. + repeated cosmos.base.v1beta1.Coin balances = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryVestingAccountsRequest is the request type for the Query/Accounts RPC method. +message QueryVestingAccountsRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryVestingAccountsResponse is the response type for the Query/Accounts RPC method. +message QueryVestingAccountsResponse { + // accounts are the existing vesting accounts + repeated google.protobuf.Any accounts = 1 [(cosmos_proto.accepts_interface) = "VestingAccount"]; + + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryVestingLockedSupplyRequest is the request type for the Query/VestingLockedSupply RPC method. +message QueryVestingLockedSupplyRequest { + // denom is the coin denom to query locked supply for. + string denom = 1; +} + +// QueryVestingAccountsResponse is the response type for the Query/VestingLockedSupply RPC method. +message QueryVestingLockedSupplyResponse { + // amount is the supply of the coin. + cosmos.base.v1beta1.Coin amount = 1 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/proto/qvesting/tx.proto b/proto/qvesting/tx.proto new file mode 100644 index 000000000..9b9aa6a4a --- /dev/null +++ b/proto/qvesting/tx.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; +package quasarlabs.quasarnode.qvesting; + +// this line is used by starport scaffolding # proto/tx/import +import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/quasarlabs/quasarnode/x/qvesting/types"; + +// Msg defines the Msg service. +service Msg { + rpc CreateVestingAccount(MsgCreateVestingAccount) returns (MsgCreateVestingAccountResponse); + // this line is used by starport scaffolding # proto/tx/rpc +} + +message MsgCreateVestingAccount { + option (gogoproto.equal) = true; + + string fromAddress = 1; + string toAddress = 2; + repeated cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + + int64 startTime = 4; + int64 endTime = 5; +} + +message MsgCreateVestingAccountResponse { +} + +// this line is used by starport scaffolding # proto/tx/message diff --git a/proto/tokenfactory/v1beta1/authorityMetadata.proto b/proto/tokenfactory/v1beta1/authorityMetadata.proto new file mode 100644 index 000000000..a8af6712a --- /dev/null +++ b/proto/tokenfactory/v1beta1/authorityMetadata.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package quasarlabs.quasarnode.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +option go_package = "github.com/quasarlabs/quasarnode/x/tokenfactory/types"; + +// DenomAuthorityMetadata specifies metadata for addresses that have specific +// capabilities over a token factory denom. Right now there is only one Admin +// permission, but is planned to be extended to the future. +message DenomAuthorityMetadata { + option (gogoproto.equal) = true; + + // Can be empty for no admin, or a valid osmosis address + string admin = 1 [ (gogoproto.moretags) = "yaml:\"admin\"" ]; +} diff --git a/proto/tokenfactory/v1beta1/genesis.proto b/proto/tokenfactory/v1beta1/genesis.proto new file mode 100644 index 000000000..2bda7fc80 --- /dev/null +++ b/proto/tokenfactory/v1beta1/genesis.proto @@ -0,0 +1,33 @@ +syntax = "proto3"; +package quasarlabs.quasarnode.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "tokenfactory/v1beta1/authorityMetadata.proto"; +import "tokenfactory/v1beta1/params.proto"; + + +option go_package = "github.com/quasarlabs/quasarnode/x/tokenfactory/types"; + +// GenesisState defines the tokenfactory module's genesis state. +message GenesisState { + // params defines the paramaters of the module. + Params params = 1 [ (gogoproto.nullable) = false ]; + + repeated GenesisDenom factory_denoms = 2 [ + (gogoproto.moretags) = "yaml:\"factory_denoms\"", + (gogoproto.nullable) = false + ]; +} + +// GenesisDenom defines a tokenfactory denom that is defined within genesis +// state. The structure contains DenomAuthorityMetadata which defines the +// denom's admin. +message GenesisDenom { + option (gogoproto.equal) = true; + + string denom = 1 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; + DenomAuthorityMetadata authority_metadata = 2 [ + (gogoproto.moretags) = "yaml:\"authority_metadata\"", + (gogoproto.nullable) = false + ]; +} diff --git a/proto/tokenfactory/v1beta1/params.proto b/proto/tokenfactory/v1beta1/params.proto new file mode 100644 index 000000000..58b7b0955 --- /dev/null +++ b/proto/tokenfactory/v1beta1/params.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; +package quasarlabs.quasarnode.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "tokenfactory/v1beta1/authorityMetadata.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +option go_package = "github.com/quasarlabs/quasarnode/x/tokenfactory/types"; + +// Params defines the parameters for the tokenfactory module. +message Params { + repeated cosmos.base.v1beta1.Coin denom_creation_fee = 1 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"denom_creation_fee\"", + (gogoproto.nullable) = false + ]; + + // if denom_creation_fee is an empty array, then this field is used to add more gas consumption + // to the base cost. + // https://github.com/CosmWasm/token-factory/issues/11 + uint64 denom_creation_gas_consume = 2 [ + (gogoproto.moretags) = "yaml:\"denom_creation_gas_consume\"", + (gogoproto.nullable) = true + ]; +} diff --git a/proto/tokenfactory/v1beta1/query.proto b/proto/tokenfactory/v1beta1/query.proto new file mode 100644 index 000000000..44167fe23 --- /dev/null +++ b/proto/tokenfactory/v1beta1/query.proto @@ -0,0 +1,71 @@ +syntax = "proto3"; +package quasarlabs.quasarnode.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "tokenfactory/v1beta1/authorityMetadata.proto"; +import "tokenfactory/v1beta1/params.proto"; + +option go_package = "github.com/quasarlabs/quasarnode/x/tokenfactory/types"; + +// Query defines the gRPC querier service. +service Query { + // Params defines a gRPC query method that returns the tokenfactory module's + // parameters. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/quasarlabs.quasarnode.tokenfactory.v1beta1/params"; + } + + // DenomAuthorityMetadata defines a gRPC query method for fetching + // DenomAuthorityMetadata for a particular denom. + rpc DenomAuthorityMetadata(QueryDenomAuthorityMetadataRequest) + returns (QueryDenomAuthorityMetadataResponse) { + option (google.api.http).get = + "/quasarlabs.quasarnode.tokenfactory.v1beta1/denoms/{denom}/authority_metadata"; + } + + // DenomsFromCreator defines a gRPC query method for fetching all + // denominations created by a specific admin/creator. + rpc DenomsFromCreator(QueryDenomsFromCreatorRequest) + returns (QueryDenomsFromCreatorResponse) { + option (google.api.http).get = + "/quasarlabs.quasarnode.tokenfactory.v1beta1/denoms_from_creator/{creator}"; + } +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1 [ (gogoproto.nullable) = false ]; +} + +// QueryDenomAuthorityMetadataRequest defines the request structure for the +// DenomAuthorityMetadata gRPC query. +message QueryDenomAuthorityMetadataRequest { + string denom = 1 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; +} + +// QueryDenomAuthorityMetadataResponse defines the response structure for the +// DenomAuthorityMetadata gRPC query. +message QueryDenomAuthorityMetadataResponse { + DenomAuthorityMetadata authority_metadata = 1 [ + (gogoproto.moretags) = "yaml:\"authority_metadata\"", + (gogoproto.nullable) = false + ]; +} + +// QueryDenomsFromCreatorRequest defines the request structure for the +// DenomsFromCreator gRPC query. +message QueryDenomsFromCreatorRequest { + string creator = 1 [ (gogoproto.moretags) = "yaml:\"creator\"" ]; +} + +// QueryDenomsFromCreatorRequest defines the response structure for the +// DenomsFromCreator gRPC query. +message QueryDenomsFromCreatorResponse { + repeated string denoms = 1 [ (gogoproto.moretags) = "yaml:\"denoms\"" ]; +} diff --git a/proto/tokenfactory/v1beta1/tx.proto b/proto/tokenfactory/v1beta1/tx.proto new file mode 100644 index 000000000..3c2688ba5 --- /dev/null +++ b/proto/tokenfactory/v1beta1/tx.proto @@ -0,0 +1,112 @@ +syntax = "proto3"; +package quasarlabs.quasarnode.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/bank/v1beta1/bank.proto"; + +option go_package = "github.com/quasarlabs/quasarnode/x/tokenfactory/types"; + +// Msg defines the tokefactory module's gRPC message service. +service Msg { + rpc CreateDenom(MsgCreateDenom) returns (MsgCreateDenomResponse); + rpc Mint(MsgMint) returns (MsgMintResponse); + rpc Burn(MsgBurn) returns (MsgBurnResponse); + rpc ChangeAdmin(MsgChangeAdmin) returns (MsgChangeAdminResponse); + rpc SetDenomMetadata(MsgSetDenomMetadata) + returns (MsgSetDenomMetadataResponse); + + // ForceTransfer is deactivated for now because we need to think through edge + // cases rpc ForceTransfer(MsgForceTransfer) returns + // (MsgForceTransferResponse); +} + +// MsgCreateDenom defines the message structure for the CreateDenom gRPC service +// method. It allows an account to create a new denom. It requires a sender +// address and a sub denomination. The (sender_address, sub_denomination) tuple +// must be unique and cannot be re-used. +// +// The resulting denom created is defined as +// . The resulting denom's admin is +// originally set to be the creator, but this can be changed later. The token +// denom does not indicate the current admin. +message MsgCreateDenom { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + // subdenom can be up to 44 "alphanumeric" characters long. + string subdenom = 2 [ (gogoproto.moretags) = "yaml:\"subdenom\"" ]; +} + +// MsgCreateDenomResponse is the return value of MsgCreateDenom +// It returns the full string of the newly created denom +message MsgCreateDenomResponse { + string new_token_denom = 1 + [ (gogoproto.moretags) = "yaml:\"new_token_denom\"" ]; +} + +// MsgMint is the sdk.Msg type for allowing an admin account to mint +// more of a token. For now, we only support minting to the sender account +message MsgMint { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.base.v1beta1.Coin amount = 2 [ + (gogoproto.moretags) = "yaml:\"amount\"", + (gogoproto.nullable) = false + ]; + string mintToAddress = 3 + [ (gogoproto.moretags) = "yaml:\"mint_to_address\"" ]; +} + +message MsgMintResponse {} + +// MsgBurn is the sdk.Msg type for allowing an admin account to burn +// a token. For now, we only support burning from the sender account. +message MsgBurn { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.base.v1beta1.Coin amount = 2 [ + (gogoproto.moretags) = "yaml:\"amount\"", + (gogoproto.nullable) = false + ]; + string burnFromAddress = 3 + [ (gogoproto.moretags) = "yaml:\"burn_from_address\"" ]; +} + +message MsgBurnResponse {} + +// MsgChangeAdmin is the sdk.Msg type for allowing an admin account to reassign +// adminship of a denom to a new account +message MsgChangeAdmin { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + string denom = 2 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; + string new_admin = 3 [ (gogoproto.moretags) = "yaml:\"new_admin\"" ]; +} + +// MsgChangeAdminResponse defines the response structure for an executed +// MsgChangeAdmin message. +message MsgChangeAdminResponse {} + +// message MsgForceTransfer { +// string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; +// cosmos.base.v1beta1.Coin amount = 2 [ +// (gogoproto.moretags) = "yaml:\"amount\"", +// (gogoproto.nullable) = false +// ]; +// string transferFromAddress = 3 +// [ (gogoproto.moretags) = "yaml:\"transfer_from_address\"" ]; +// string transferToAddress = 4 +// [ (gogoproto.moretags) = "yaml:\"transfer_to_address\"" ]; +// } + +// message MsgForceTransferResponse {} + +// MsgSetDenomMetadata is the sdk.Msg type for allowing an admin account to set +// the denom's bank metadata +message MsgSetDenomMetadata { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.bank.v1beta1.Metadata metadata = 2 [ + (gogoproto.moretags) = "yaml:\"metadata\"", + (gogoproto.nullable) = false + ]; +} + +// MsgSetDenomMetadataResponse defines the response structure for an executed +// MsgSetDenomMetadata message. +message MsgSetDenomMetadataResponse {} \ No newline at end of file diff --git a/tests/e2e/README.md b/tests/e2e/README.md index b40ac3731..964b17bb0 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -68,6 +68,7 @@ flexibility to either run the complete test suite or execute specific test cases To execute all test cases, simply run the following command: ```bash +cd tests/e2e make test-e2e ``` @@ -81,6 +82,7 @@ If you want to run specific test cases instead of the entire suite, you can do s use the following command: ```bash +cd tests/e2e CASES="case1 case2 case3" make test-e2e ``` diff --git a/testutil/keeper/common.go b/testutil/keeper/common.go index 52b480f5c..60082c414 100644 --- a/testutil/keeper/common.go +++ b/testutil/keeper/common.go @@ -9,8 +9,12 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) func (kf KeeperFactory) ParamsKeeper() paramskeeper.Keeper { @@ -60,3 +64,39 @@ func (kf KeeperFactory) CapabilityKeeper() capabilitykeeper.Keeper { return *capabilityKeeper } + +func (kf KeeperFactory) StakingKeeper(paramsKeeper paramskeeper.Keeper, + accountKeeper authkeeper.AccountKeeper, + // bankKeeper bankkeeper.BaseKeeper) stakingkeeper.Keeper { + bankKeeper bankkeeper.Keeper) stakingkeeper.Keeper { + storeKey := sdk.NewKVStoreKey(stakingtypes.StoreKey) + kf.StateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, kf.DB) + + subspace := paramsKeeper.Subspace(stakingtypes.ModuleName) + stakingKeeper := stakingkeeper.NewKeeper( + kf.EncodingConfig.Marshaler, storeKey, accountKeeper, bankKeeper, subspace) + + return stakingKeeper +} + +func (kf KeeperFactory) DistributionKeeper(paramsKeeper paramskeeper.Keeper, + accountKeeper authkeeper.AccountKeeper, + // bankKeeper bankkeeper.BaseKeeper, + bankKeeper bankkeeper.Keeper, + stakingKeeper stakingkeeper.Keeper, + feeCollectorName string, + blockedAddrs map[string]bool) distrkeeper.Keeper { + + storeKey := sdk.NewKVStoreKey(distrtypes.StoreKey) + kf.StateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, kf.DB) + subspace := paramsKeeper.Subspace(distrtypes.ModuleName) + disrKeeper := distrkeeper.NewKeeper(kf.EncodingConfig.Marshaler, + storeKey, + subspace, + accountKeeper, + bankKeeper, + stakingKeeper, + feeCollectorName, + blockedAddrs) + return disrKeeper +} diff --git a/testutil/keeper/qvesting.go b/testutil/keeper/qvesting.go new file mode 100644 index 000000000..a00dc323f --- /dev/null +++ b/testutil/keeper/qvesting.go @@ -0,0 +1,98 @@ +package keeper + +import ( + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + typesparams "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/quasarlabs/quasarnode/x/qvesting/keeper" + "github.com/quasarlabs/quasarnode/x/qvesting/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmdb "github.com/tendermint/tm-db" +) + +func QVestingKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { + storeKey := sdk.NewKVStoreKey(types.StoreKey) + memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) + + db := tmdb.NewMemDB() + stateStore := store.NewCommitMultiStore(db) + stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) + stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) + require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + + paramsSubspace := typesparams.NewSubspace(cdc, + types.Amino, + storeKey, + memStoreKey, + "QVestingParams", + ) + k := keeper.NewKeeper( + cdc, + storeKey, + memStoreKey, + paramsSubspace, + nil, + nil, + ) + + ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) + + // Initialize params + k.SetParams(ctx, types.DefaultParams()) + + return k, ctx +} + +func (kf KeeperFactory) QVestingKeeper(paramsKeeper paramskeeper.Keeper, accountKeeper authkeeper.AccountKeeper, + bankKeeper bankkeeper.Keeper) keeper.Keeper { + + storeKey := sdk.NewKVStoreKey(types.StoreKey) + kf.StateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, kf.DB) + + //storeKey := sdk.NewKVStoreKey(types.StoreKey) + memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) + + //db := tmdb.NewMemDB() + //stateStore := store.NewCommitMultiStore(db) + //stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) + //stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) + //require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + + //paramsSubspace := typesparams.NewSubspace(cdc, + // types.Amino, + // storeKey, + // memStoreKey, + // "QVestingParams", + //) + paramsSubspace := paramsKeeper.Subspace(types.ModuleName) + + k := keeper.NewKeeper( + cdc, + storeKey, + memStoreKey, + paramsSubspace, + accountKeeper, + bankKeeper, + ) + + // Initialize params + // k.SetParams(ctx, types.DefaultParams()) + + return *k +} diff --git a/testutil/keeper/tfkeeper.go b/testutil/keeper/tfkeeper.go new file mode 100644 index 000000000..03ffe8735 --- /dev/null +++ b/testutil/keeper/tfkeeper.go @@ -0,0 +1,35 @@ +package keeper + +import ( + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +func (kf KeeperFactory) TfKeeper(paramsKeeper paramskeeper.Keeper, + accountKeeper authkeeper.AccountKeeper, + bankKeeper bankkeeper.Keeper, + communityPoolKeeper distrkeeper.Keeper) keeper.Keeper { + storeKey := sdk.NewKVStoreKey(types.StoreKey) + + kf.StateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, kf.DB) + + paramsSubspace := paramsKeeper.Subspace(types.ModuleName) + tfKeeper := keeper.NewKeeper( + storeKey, + paramsSubspace, + accountKeeper, + bankKeeper, + communityPoolKeeper) + + return tfKeeper +} + +func (kf KeeperFactory) SetTFDefaultParams(k keeper.Keeper) { + k.SetParams(kf.Ctx, types.DefaultParams()) +} diff --git a/testutil/setup.go b/testutil/setup.go index 440726ef4..7d51b42bf 100644 --- a/testutil/setup.go +++ b/testutil/setup.go @@ -1,6 +1,10 @@ package testutil import ( + "github.com/cosmos/cosmos-sdk/simapp" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "testing" "github.com/cosmos/cosmos-sdk/codec" @@ -11,8 +15,10 @@ import ( bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + stakingKeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" icacontrollertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" "github.com/golang/mock/gomock" "github.com/quasarlabs/quasarnode/app" @@ -23,7 +29,10 @@ import ( qosmokeeper "github.com/quasarlabs/quasarnode/x/qoracle/osmosis/keeper" qosmotypes "github.com/quasarlabs/quasarnode/x/qoracle/osmosis/types" qtransferkeeper "github.com/quasarlabs/quasarnode/x/qtransfer/keeper" + qvestingkeeper "github.com/quasarlabs/quasarnode/x/qvesting/keeper" + tfkeeper "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmdb "github.com/tendermint/tm-db" @@ -44,6 +53,32 @@ func init() { config.SetBech32PrefixForConsensusNode(consNodeAddressPrefix, consNodePubKeyPrefix) config.Seal() } +func CreateRandomAccounts(numAccts int) []sdk.AccAddress { + testAddrs := make([]sdk.AccAddress, numAccts) + for i := 0; i < numAccts; i++ { + pk := ed25519.GenPrivKey().PubKey() + testAddrs[i] = sdk.AccAddress(pk.Address()) + } + + return testAddrs +} + +// FundAcc funds target address with specified amount. +func (ts *TestSetup) FundAcc(t testing.TB, acc sdk.AccAddress, amounts sdk.Coins) { + err := simapp.FundAccount(ts.Keepers.BankKeeper, ts.Ctx, acc, amounts) + require.NoError(t, err) +} + +// FundModuleAcc funds target modules with specified amount. +func (ts *TestSetup) FundModuleAcc(t testing.TB, moduleName string, amounts sdk.Coins) { + err := simapp.FundModuleAccount(ts.Keepers.BankKeeper, ts.Ctx, moduleName, amounts) + require.NoError(t, err) +} + +func (ts *TestSetup) MintCoins(t testing.TB, coins sdk.Coins) { + err := ts.Keepers.BankKeeper.MintCoins(ts.Ctx, minttypes.ModuleName, coins) + require.NoError(t, err) +} func NewTestSetup(t testing.TB, controller ...*gomock.Controller) *TestSetup { // Test setup params @@ -92,6 +127,9 @@ func NewTestSetup(t testing.TB, controller ...*gomock.Controller) *TestSetup { bankKeeper := factory.BankKeeper(paramsKeeper, accountKeeper, blockedMaccAddresses) capabilityKeeper := factory.CapabilityKeeper() capabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) + stakingKeeper := factory.StakingKeeper(paramsKeeper, accountKeeper, bankKeeper) + distrKeeper := factory.DistributionKeeper(paramsKeeper, accountKeeper, bankKeeper, stakingKeeper, + "feeCollectorName", blockedMaccAddresses) qosmoScopedKeeper := capabilityKeeper.ScopeToModule(qosmotypes.SubModuleName) qoracleKeeper := factory.QoracleKeeper(paramsKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) @@ -99,6 +137,8 @@ func NewTestSetup(t testing.TB, controller ...*gomock.Controller) *TestSetup { qoracleKeeper.RegisterPoolOracle(qosmosisKeeper) qoracleKeeper.Seal() qtransferkeeper := factory.QTransferKeeper(paramsKeeper, accountKeeper) + qvestingKeeper := factory.QVestingKeeper(paramsKeeper, accountKeeper, bankKeeper) + tfKeeper := factory.TfKeeper(paramsKeeper, accountKeeper, bankKeeper, distrKeeper) // Note: the relative order of LoadLatestVersion and Set*DefaultParams is important. // Setting params before loading stores causes store does not exist error. @@ -108,7 +148,12 @@ func NewTestSetup(t testing.TB, controller ...*gomock.Controller) *TestSetup { factory.SetQoracleDefaultParams(qoracleKeeper) factory.SetQosmosisDefaultParams(qosmosisKeeper) + testAccts := CreateRandomAccounts(3) + + // Init Genesis of Keepers + distrGendata := distrtypes.GenesisState{Params: distrtypes.DefaultParams()} + distrKeeper.InitGenesis(ctx, distrGendata) return &TestSetup{ Ctx: ctx, Cdc: encodingConfig.Marshaler, @@ -126,7 +171,10 @@ func NewTestSetup(t testing.TB, controller ...*gomock.Controller) *TestSetup { QoracleKeeper: qoracleKeeper, QosmosisKeeper: qosmosisKeeper, QTransfer: qtransferkeeper, + QVestingKeeper: qvestingKeeper, + TfKeeper: tfKeeper, }, + TestAccs: testAccts, } } @@ -134,8 +182,9 @@ type TestSetup struct { Ctx sdk.Context Cdc codec.Codec - Keepers *testKeepers - Mocks *testMocks + Keepers *testKeepers + Mocks *testMocks + TestAccs []sdk.AccAddress } type testMocks struct { @@ -143,12 +192,16 @@ type testMocks struct { } type testKeepers struct { - ParamsKeeper paramskeeper.Keeper - EpochsKeeper *epochskeeper.Keeper - AccountKeeper authkeeper.AccountKeeper - BankKeeper bankkeeper.Keeper - CapabilityKeeper capabilitykeeper.Keeper - QoracleKeeper qoraclekeeper.Keeper - QosmosisKeeper qosmokeeper.Keeper - QTransfer qtransferkeeper.Keeper + ParamsKeeper paramskeeper.Keeper + EpochsKeeper *epochskeeper.Keeper + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + StakingKeeper stakingKeeper.Keeper + DistributedKeeper distrkeeper.Keeper + CapabilityKeeper capabilitykeeper.Keeper + QoracleKeeper qoraclekeeper.Keeper + QosmosisKeeper qosmokeeper.Keeper + QTransfer qtransferkeeper.Keeper + QVestingKeeper qvestingkeeper.Keeper + TfKeeper tfkeeper.Keeper } diff --git a/x/qvesting/README.md b/x/qvesting/README.md new file mode 100644 index 000000000..52bf81c81 --- /dev/null +++ b/x/qvesting/README.md @@ -0,0 +1,46 @@ +--- +title: "QVesting" +excerpt: "" +--- + +# The QVesting Module + +The `x/qvesting` module provides a way for managing vesting schedules in the Quasar foundation to +use `create-vesting-account` message for investors who had invested but failed to provide address at the time of +genesis. + +The `x/qvesting` module is a custom implementation built on top of the built-in `x/auth/vesting` module to address the +limitations. This custom module extends the functionality of the `x/auth/vesting` module to +provide better flexibility and support for defining the start time for vesting schedules as well as implementing queries for spendable balances and iterate existing vesting accounts. + +## Keeper functions + +- `CreateVestingAccount()` +- `AddVestingAccount()` +- `IterateVestingAccounts()` + +## State + +Misc + +- `GenesisState` + +## Queries + +- `QueryParams` +- `QuerySpendableBalances` +- `QueryVestingAccounts` + +## Events + +`qvesting` module emits the following events: + +Type: Attribute Key → Attribute Value +-------------------------------------------------- + +create_vesting_account: +- module → qvesting +- amount → {denomAmount} +- start_time → {unixTimestamp} +- end_time → {unixTimestamp} +- acc → {accAddress} \ No newline at end of file diff --git a/x/qvesting/client/cli/query.go b/x/qvesting/client/cli/query.go new file mode 100644 index 000000000..9c6730633 --- /dev/null +++ b/x/qvesting/client/cli/query.go @@ -0,0 +1,162 @@ +package cli + +import ( + "context" + "fmt" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/quasarlabs/quasarnode/x/qvesting/types" + "github.com/spf13/cobra" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd() *cobra.Command { + // Group qvesting queries under a subcommand + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + CmdQueryParams(), + CmdQuerySpendableBalances(), + CmdQueryVestingAccounts(), + CmdQueryVestingLockedSupply(), + ) + + return cmd +} + +func CmdQueryParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "shows the parameters of the module", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Params(context.Background(), &types.QueryParamsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func CmdQuerySpendableBalances() *cobra.Command { + cmd := &cobra.Command{ + Use: "spendable-balances [address]", + Short: "shows the spendable balances in a paginated response for a given vesting account", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) (err error) { + reqAddress := args[0] + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + ctx := cmd.Context() + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + params := &types.QuerySpendableBalancesRequest{ + Address: reqAddress, + Pagination: pageReq, + } + + res, err := queryClient.SpendableBalances(ctx, params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "spendable-balances") + + return cmd +} + +func CmdQueryVestingAccounts() *cobra.Command { + cmd := &cobra.Command{ + Use: "accounts", + Short: "shows the existing vesting accounts in a paginated response", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + ctx := cmd.Context() + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + params := &types.QueryVestingAccountsRequest{ + Pagination: pageReq, + } + + res, err := queryClient.VestingAccounts(ctx, params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddPaginationFlagsToCmd(cmd, "vesting-accounts") + + return cmd +} + +func CmdQueryVestingLockedSupply() *cobra.Command { + cmd := &cobra.Command{ + Use: "locked-supply [denom]", + Short: "shows the total locked-supply in vesting accounts for a given denom", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) (err error) { + reqDenom := args[0] + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + ctx := cmd.Context() + + res, err := queryClient.VestingLockedSupply(ctx, &types.QueryVestingLockedSupplyRequest{Denom: reqDenom}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/qvesting/client/cli/tx.go b/x/qvesting/client/cli/tx.go new file mode 100644 index 000000000..74924b542 --- /dev/null +++ b/x/qvesting/client/cli/tx.go @@ -0,0 +1,84 @@ +package cli + +import ( + "fmt" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/spf13/cast" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/quasarlabs/quasarnode/x/qvesting/types" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(CmdCreateVestingAccount()) + // this line is used by starport scaffolding # 1 + + return cmd +} + +func CmdCreateVestingAccount() *cobra.Command { + cmd := &cobra.Command{ + Use: "create-vesting-account [to-address] [amount] [start-time] [end-time]", + Short: "Create a new vesting account funded with an allocation of tokens.", + Long: `Create a new vesting account funded with an allocation of tokens. +The account can be a continuous vesting account. The start_time and end_time must be +provided as a UNIX epoch timestamp.`, + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) (err error) { + argToAddress, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + argAmount, err := sdk.ParseCoinsNormalized(args[1]) + if err != nil { + return err + } + + argStartTime, err := cast.ToInt64E(args[2]) + if err != nil { + return err + } + + argEndTime, err := cast.ToInt64E(args[3]) + if err != nil { + return err + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgCreateVestingAccount( + clientCtx.GetFromAddress().String(), + argToAddress, + argAmount, + argStartTime, + argEndTime, + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/qvesting/genesis.go b/x/qvesting/genesis.go new file mode 100644 index 000000000..c0255fb57 --- /dev/null +++ b/x/qvesting/genesis.go @@ -0,0 +1,24 @@ +package qvesting + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/quasarlabs/quasarnode/x/qvesting/keeper" + "github.com/quasarlabs/quasarnode/x/qvesting/types" +) + +// InitGenesis initializes the capability module's state from a provided genesis +// state. +func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { + // this line is used by starport scaffolding # genesis/module/init + k.SetParams(ctx, genState.Params) +} + +// ExportGenesis returns the capability module's exported genesis. +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { + genesis := types.DefaultGenesis() + genesis.Params = k.GetParams(ctx) + + // this line is used by starport scaffolding # genesis/module/export + + return genesis +} diff --git a/x/qvesting/handler.go b/x/qvesting/handler.go new file mode 100644 index 000000000..a4564a2fe --- /dev/null +++ b/x/qvesting/handler.go @@ -0,0 +1,29 @@ +package qvesting + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/quasarlabs/quasarnode/x/qvesting/keeper" + "github.com/quasarlabs/quasarnode/x/qvesting/types" +) + +// NewHandler ... +func NewHandler(k keeper.Keeper) sdk.Handler { + msgServer := keeper.NewMsgServerImpl(k) + + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case *types.MsgCreateVestingAccount: + res, err := msgServer.CreateVestingAccount(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + // this line is used by starport scaffolding # 1 + default: + errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) + } + } +} diff --git a/x/qvesting/keeper/grpc_query.go b/x/qvesting/keeper/grpc_query.go new file mode 100644 index 000000000..e3faf3b28 --- /dev/null +++ b/x/qvesting/keeper/grpc_query.go @@ -0,0 +1,138 @@ +package keeper + +import ( + "context" + "fmt" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store/mem" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" + "github.com/quasarlabs/quasarnode/x/qvesting/types" + "google.golang.org/grpc/codes" + + "google.golang.org/grpc/status" +) + +var _ types.QueryServer = Keeper{} + +func (k Keeper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(c) + + return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil +} + +// SpendableBalances implements a gRPC query handler for retrieving an account's +// spendable balances. +func (k Keeper) SpendableBalances(ctx context.Context, req *types.QuerySpendableBalancesRequest) (*types.QuerySpendableBalancesResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + addr, err := sdk.AccAddressFromBech32(req.Address) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid address: %s", err.Error()) + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + + spendable := k.bankKeeper.SpendableCoins(sdkCtx, addr) + + memStore := mem.NewStore() + for i, coin := range spendable { + memStore.Set(sdk.Uint64ToBigEndian(uint64(i)), k.cdc.MustMarshal(&coin)) + } + + var paginatedSpendable sdk.Coins + pageRes, err := query.Paginate(memStore, req.Pagination, func(key []byte, value []byte) error { + var coin sdk.Coin + k.cdc.MustUnmarshal(value, &coin) + paginatedSpendable = append(paginatedSpendable, coin) + return nil + }) + + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "paginate: %v", err) + } + + return &types.QuerySpendableBalancesResponse{ + Balances: paginatedSpendable, + Pagination: pageRes, + }, nil +} + +func (k Keeper) VestingAccounts(c context.Context, req *types.QueryVestingAccountsRequest) (*types.QueryVestingAccountsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + store := ctx.KVStore(k.storeKey) + accountsStore := prefix.NewStore(store, types.VestingAccountStoreKeyPrefix) + + var accounts []*codectypes.Any + pageRes, err := query.Paginate(accountsStore, req.Pagination, func(key, value []byte) error { + addr := sdk.AccAddress(key) + acct := k.accountKeeper.GetAccount(ctx, addr) + vestingAcct, ok := acct.(exported.VestingAccount) + if !ok { + return fmt.Errorf("account is not vesting account: %s", addr.String()) + } + + any, err := codectypes.NewAnyWithValue(vestingAcct) + if err != nil { + return err + } + accounts = append(accounts, any) + return nil + }) + + if err != nil { + return nil, status.Errorf(codes.Internal, "paginate: %v", err) + } + + return &types.QueryVestingAccountsResponse{Accounts: accounts, Pagination: pageRes}, err + +} + +// VestingLockedSupply returns the total amount of locked supply for a given denomination across all vesting accounts. +// The locked supply of a vesting account is the total balance of the account minus the spendable balance. +// The function iterates over all the vesting accounts, and for each account, it retrieves the balance for the requested denomination +// and subtracts the spendable amount. The result is added to the total locked supply. +func (k Keeper) VestingLockedSupply(ctx context.Context, req *types.QueryVestingLockedSupplyRequest) (*types.QueryVestingLockedSupplyResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + resAmount := sdk.NewInt(0) + + // iterate vesting accounts passing a callback function to invoke + err := k.iterateVestingAccounts(sdkCtx, func(addr sdk.AccAddress) error { + // get the total vesting account balance for requested denom + accBalance := k.bankKeeper.GetBalance(sdkCtx, addr, req.Denom) + + // get the total vesting account spendable balances + spendableCoins := k.bankKeeper.SpendableCoins(sdkCtx, addr) + // iterate spendable balances looking for requested denom to subtract from total accBalance.Amount + for _, coin := range spendableCoins { + // if denom exists and amount is greater than 0 subtract it + if coin.Denom == req.Denom && coin.Amount.GT(sdk.NewInt(0)) { + accBalance.Amount = accBalance.Amount.Sub(coin.Amount) + } + } + + resAmount = resAmount.Add(accBalance.Amount) + return nil + }) + // Handle error from iteration of vesting accounts + if err != nil { + return nil, err + } + + return &types.QueryVestingLockedSupplyResponse{Amount: sdk.Coin{Denom: req.Denom, Amount: resAmount}}, nil +} diff --git a/x/qvesting/keeper/grpc_query_test.go b/x/qvesting/keeper/grpc_query_test.go new file mode 100644 index 000000000..4e1be6413 --- /dev/null +++ b/x/qvesting/keeper/grpc_query_test.go @@ -0,0 +1,21 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + testkeeper "github.com/quasarlabs/quasarnode/testutil/keeper" + "github.com/quasarlabs/quasarnode/x/qvesting/types" + "github.com/stretchr/testify/require" +) + +func TestParamsQuery(t *testing.T) { + keeper, ctx := testkeeper.QVestingKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + params := types.DefaultParams() + keeper.SetParams(ctx, params) + + response, err := keeper.Params(wctx, &types.QueryParamsRequest{}) + require.NoError(t, err) + require.Equal(t, &types.QueryParamsResponse{Params: params}, response) +} diff --git a/x/qvesting/keeper/keeper.go b/x/qvesting/keeper/keeper.go new file mode 100644 index 000000000..eda04cb13 --- /dev/null +++ b/x/qvesting/keeper/keeper.go @@ -0,0 +1,93 @@ +package keeper + +import ( + "fmt" + "github.com/cosmos/cosmos-sdk/store/prefix" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" + "github.com/tendermint/tendermint/libs/log" + "google.golang.org/grpc/grpclog" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/quasarlabs/quasarnode/x/qvesting/types" +) + +type ( + Keeper struct { + cdc codec.BinaryCodec + storeKey sdk.StoreKey + memKey sdk.StoreKey + paramstore paramtypes.Subspace + + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + } +) + +func NewKeeper( + cdc codec.BinaryCodec, + storeKey, + memKey sdk.StoreKey, + ps paramtypes.Subspace, + + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, +) *Keeper { + // set KeyTable if it has not already been set + if !ps.HasKeyTable() { + ps = ps.WithKeyTable(types.ParamKeyTable()) + } + + return &Keeper{ + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + paramstore: ps, + + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + } +} + +func (k Keeper) AddVestingAccount(ctx sdk.Context, addr sdk.AccAddress) { + store := ctx.KVStore(k.storeKey) + store.Set(types.VestingAccountStoreKey(addr), []byte{}) +} + +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +// iterateVestingAccounts iterates over all vesting accounts and invokes a callback function on each of them. +func (k Keeper) iterateVestingAccounts(sdkCtx sdk.Context, callback func(addr sdk.AccAddress) error) error { + store := sdkCtx.KVStore(k.storeKey) + accountsStore := prefix.NewStore(store, types.VestingAccountStoreKeyPrefix) + iterator := accountsStore.Iterator(nil, nil) + + // empty allocated resources after execution + defer func(iterator storetypes.Iterator) { + err := iterator.Close() + if err != nil { + grpclog.Infof("Failed to close iterator for %s", err) + } + }(iterator) + + for ; iterator.Valid(); iterator.Next() { + key := iterator.Key() + addr := sdk.AccAddress(key) + acct := k.accountKeeper.GetAccount(sdkCtx, addr) + _, ok := acct.(exported.VestingAccount) + if !ok { + return fmt.Errorf("account is not vesting account: %s", addr.String()) + } + + // invoke the callback function for the iterated vesting account + if err := callback(addr); err != nil { + return err + } + } + + return nil +} diff --git a/x/qvesting/keeper/msg_server.go b/x/qvesting/keeper/msg_server.go new file mode 100644 index 000000000..3541a2e96 --- /dev/null +++ b/x/qvesting/keeper/msg_server.go @@ -0,0 +1,103 @@ +package keeper + +import ( + "context" + "github.com/armon/go-metrics" + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + "github.com/quasarlabs/quasarnode/x/qvesting/types" + "strconv" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +func (k msgServer) CreateVestingAccount(goCtx context.Context, msg *types.MsgCreateVestingAccount) (*types.MsgCreateVestingAccountResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + ak := k.accountKeeper + bk := k.bankKeeper + + // Validate msg.StartTime against the current block time to be higher + blockTime := ctx.BlockTime().Unix() + if msg.StartTime <= blockTime { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "start or end time must be higher than the current block time") + } + + if err := bk.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { + return nil, err + } + + from, err := sdk.AccAddressFromBech32(msg.FromAddress) + if err != nil { + return nil, err + } + to, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return nil, err + } + + if bk.BlockedAddr(to) { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.ToAddress) + } + + if acc := ak.GetAccount(ctx, to); acc != nil { + return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "account %s already exists", msg.ToAddress) + } + + baseAccount := ak.NewAccountWithAddress(ctx, to) + if _, ok := baseAccount.(*authtypes.BaseAccount); !ok { + return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid account type; expected: BaseAccount, got: %T", baseAccount) + } + + baseVestingAccount := vestingtypes.NewBaseVestingAccount(baseAccount.(*authtypes.BaseAccount), msg.Amount.Sort(), msg.EndTime) + + acc := vestingtypes.NewContinuousVestingAccountRaw(baseVestingAccount, msg.StartTime) + + ak.SetAccount(ctx, acc) + k.AddVestingAccount(ctx, acc.GetAddress()) + + defer func() { + telemetry.IncrCounter(1, "new", "account") + + for _, a := range msg.Amount { + if a.Amount.IsInt64() { + telemetry.SetGaugeWithLabels( + []string{"tx", "msg", "create_vesting_account"}, + float32(a.Amount.Int64()), + []metrics.Label{telemetry.NewLabel("denom", a.Denom)}, + ) + } + } + }() + + err = bk.SendCoins(ctx, from, to, msg.Amount) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(types.AttributeKeyStartTime, strconv.FormatInt(msg.StartTime, 10)), + sdk.NewAttribute(types.AttributeKeyEndTime, strconv.FormatInt(msg.EndTime, 10)), + sdk.NewAttribute(types.AttributeKeyFromAccount, msg.FromAddress), + sdk.NewAttribute(types.AttributeKeyToAccount, msg.ToAddress), + ), + ) + + return &types.MsgCreateVestingAccountResponse{}, nil +} diff --git a/x/qvesting/keeper/params.go b/x/qvesting/keeper/params.go new file mode 100644 index 000000000..ace520598 --- /dev/null +++ b/x/qvesting/keeper/params.go @@ -0,0 +1,16 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/quasarlabs/quasarnode/x/qvesting/types" +) + +// GetParams get all parameters as types.Params +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + return types.NewParams() +} + +// SetParams set the params +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramstore.SetParamSet(ctx, ¶ms) +} diff --git a/x/qvesting/keeper/params_test.go b/x/qvesting/keeper/params_test.go new file mode 100644 index 000000000..52b929fae --- /dev/null +++ b/x/qvesting/keeper/params_test.go @@ -0,0 +1,18 @@ +package keeper_test + +import ( + "testing" + + testkeeper "github.com/quasarlabs/quasarnode/testutil/keeper" + "github.com/quasarlabs/quasarnode/x/qvesting/types" + "github.com/stretchr/testify/require" +) + +func TestGetParams(t *testing.T) { + k, ctx := testkeeper.QVestingKeeper(t) + params := types.DefaultParams() + + k.SetParams(ctx, params) + + require.EqualValues(t, params, k.GetParams(ctx)) +} diff --git a/x/qvesting/module.go b/x/qvesting/module.go new file mode 100644 index 000000000..2be3216a4 --- /dev/null +++ b/x/qvesting/module.go @@ -0,0 +1,182 @@ +package qvesting + +import ( + "context" + "encoding/json" + "fmt" + // this line is used by starport scaffolding # 1 + + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/bank/client/rest" + "github.com/quasarlabs/quasarnode/x/qvesting/client/cli" + "github.com/quasarlabs/quasarnode/x/qvesting/keeper" + "github.com/quasarlabs/quasarnode/x/qvesting/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the capability module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the capability module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the capability module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { + rest.RegisterHandlers(clientCtx, rtr) +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + // this line is used by starport scaffolding # 2 + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + return + } +} + +// GetTxCmd returns the capability module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the capability module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper +} + +func NewAppModule( + cdc codec.Codec, + keeper keeper.Keeper, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + } +} + +// Name returns the capability module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// Route returns the capability module's message routing key. +func (am AppModule) Route() sdk.Route { + return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) +} + +// QuerierRoute returns the capability module's query routing key. +func (AppModule) QuerierRoute() string { return types.QuerierRoute } + +// LegacyQuerierHandler returns the capability module's Querier. +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// RegisterInvariants registers the capability module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the capability module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + InitGenesis(ctx, am.keeper, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion implements ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 2 } + +// BeginBlock executes all ABCI BeginBlock logic respective to the capability module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock executes all ABCI EndBlock logic respective to the capability module. It +// returns no validator updates. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/qvesting/types/codec.go b/x/qvesting/types/codec.go new file mode 100644 index 000000000..35729ffd5 --- /dev/null +++ b/x/qvesting/types/codec.go @@ -0,0 +1,29 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + // this line is used by starport scaffolding # 1 + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgCreateVestingAccount{}, "qvesting/CreateVestingAccount", nil) + // this line is used by starport scaffolding # 2 +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgCreateVestingAccount{}, + ) + // this line is used by starport scaffolding # 3 + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + Amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) +) diff --git a/x/qvesting/types/constants.go b/x/qvesting/types/constants.go new file mode 100644 index 000000000..96a802992 --- /dev/null +++ b/x/qvesting/types/constants.go @@ -0,0 +1,14 @@ +package types + +const ( + AttributeKeyFromAccount = "from_acc" + AttributeKeyToAccount = "to_acc" + AttributeKeyStartTime = "start_time" + AttributeKeyEndTime = "end_time" + + // AttributeValueCategory is an alias for the message event value. + AttributeValueCategory = ModuleName + + // AttributeValueAction is an alias for the message event value. + AttributeValueAction = TypeMsgCreateVestingAccount +) diff --git a/x/qvesting/types/expected_keepers.go b/x/qvesting/types/expected_keepers.go new file mode 100644 index 000000000..96185efb8 --- /dev/null +++ b/x/qvesting/types/expected_keepers.go @@ -0,0 +1,24 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// AccountKeeper defines the expected account keeper used for simulations (noalias) +type AccountKeeper interface { + GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI + NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) types.AccountI + SetAccount(ctx sdk.Context, acc types.AccountI) +} + +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + // Keeper + IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + BlockedAddr(addr sdk.AccAddress) bool + // View + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} diff --git a/x/qvesting/types/genesis.go b/x/qvesting/types/genesis.go new file mode 100644 index 000000000..0e6aaf492 --- /dev/null +++ b/x/qvesting/types/genesis.go @@ -0,0 +1,17 @@ +package types + +// DefaultGenesis returns the default Capability genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + // this line is used by starport scaffolding # genesis/types/default + Params: DefaultParams(), + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + // this line is used by starport scaffolding # genesis/types/validate + + return gs.Params.Validate() +} diff --git a/x/qvesting/types/genesis.pb.go b/x/qvesting/types/genesis.pb.go new file mode 100644 index 000000000..2381891f8 --- /dev/null +++ b/x/qvesting/types/genesis.pb.go @@ -0,0 +1,321 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: qvesting/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the qvesting module's genesis state. +type GenesisState struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_fab9e47ea7335c2b, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "quasarlabs.quasarnode.qvesting.GenesisState") +} + +func init() { proto.RegisterFile("qvesting/genesis.proto", fileDescriptor_fab9e47ea7335c2b) } + +var fileDescriptor_fab9e47ea7335c2b = []byte{ + // 198 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2b, 0x2c, 0x4b, 0x2d, + 0x2e, 0xc9, 0xcc, 0x4b, 0xd7, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, + 0x2f, 0xc9, 0x17, 0x92, 0x2b, 0x2c, 0x4d, 0x2c, 0x4e, 0x2c, 0xca, 0x49, 0x4c, 0x2a, 0xd6, 0x83, + 0x30, 0xf3, 0xf2, 0x53, 0x52, 0xf5, 0x60, 0xaa, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x4a, + 0xf5, 0x41, 0x2c, 0x88, 0x2e, 0x29, 0x51, 0xb8, 0x69, 0x05, 0x89, 0x45, 0x89, 0xb9, 0x50, 0xc3, + 0x94, 0x42, 0xb8, 0x78, 0xdc, 0x21, 0xa6, 0x07, 0x97, 0x24, 0x96, 0xa4, 0x0a, 0xb9, 0x70, 0xb1, + 0x41, 0xe4, 0x25, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0xd4, 0xf4, 0xf0, 0xdb, 0xa6, 0x17, 0x00, + 0x56, 0xed, 0xc4, 0x72, 0xe2, 0x9e, 0x3c, 0x43, 0x10, 0x54, 0xaf, 0x93, 0xf7, 0x89, 0x47, 0x72, + 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, + 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x19, 0xa6, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, + 0xe7, 0xe7, 0xea, 0x23, 0x4c, 0xd6, 0x47, 0x98, 0xac, 0x5f, 0xa1, 0x0f, 0x77, 0x69, 0x49, 0x65, + 0x41, 0x6a, 0x71, 0x12, 0x1b, 0xd8, 0xa5, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x65, 0x0a, + 0x3a, 0x55, 0x10, 0x01, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/qvesting/types/genesis_test.go b/x/qvesting/types/genesis_test.go new file mode 100644 index 000000000..080fec36c --- /dev/null +++ b/x/qvesting/types/genesis_test.go @@ -0,0 +1,40 @@ +package types_test + +import ( + "testing" + + "github.com/quasarlabs/quasarnode/x/qvesting/types" + "github.com/stretchr/testify/require" +) + +func TestGenesisState_Validate(t *testing.T) { + for _, tc := range []struct { + desc string + genState *types.GenesisState + valid bool + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + valid: true, + }, + { + desc: "valid genesis state", + genState: &types.GenesisState{ + + // this line is used by starport scaffolding # types/genesis/validField + }, + valid: true, + }, + // this line is used by starport scaffolding # types/genesis/testcase + } { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + if tc.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/x/qvesting/types/keys.go b/x/qvesting/types/keys.go new file mode 100644 index 000000000..cb32b305c --- /dev/null +++ b/x/qvesting/types/keys.go @@ -0,0 +1,31 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // ModuleName defines the module name + ModuleName = "qvesting" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey is the message route for slashing + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key + QuerierRoute = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_qvesting" +) + +var ( + VestingAccountStoreKeyPrefix = []byte{0x01} +) + +// VestingAccountStoreKey turn an address to key used to record it in the vesting store +func VestingAccountStoreKey(addr sdk.AccAddress) []byte { + return append(VestingAccountStoreKeyPrefix, addr.Bytes()...) +} diff --git a/x/qvesting/types/msgs.go b/x/qvesting/types/msgs.go new file mode 100644 index 000000000..e6a0b240d --- /dev/null +++ b/x/qvesting/types/msgs.go @@ -0,0 +1,73 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const TypeMsgCreateVestingAccount = "create_vesting_account" + +var _ sdk.Msg = &MsgCreateVestingAccount{} + +func NewMsgCreateVestingAccount(fromAddress string, toAddress sdk.AccAddress, amount sdk.Coins, startTime int64, endTime int64) *MsgCreateVestingAccount { + return &MsgCreateVestingAccount{ + FromAddress: fromAddress, + ToAddress: toAddress.String(), + Amount: amount, + StartTime: startTime, + EndTime: endTime, + } +} + +func (msg *MsgCreateVestingAccount) Route() string { + return RouterKey +} + +func (msg *MsgCreateVestingAccount) Type() string { + return TypeMsgCreateVestingAccount +} + +func (msg *MsgCreateVestingAccount) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.FromAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgCreateVestingAccount) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgCreateVestingAccount) ValidateBasic() error { + from, err := sdk.AccAddressFromBech32(msg.FromAddress) + if err != nil { + return err + } + to, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return err + } + if err := sdk.VerifyAddressFormat(from); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid sender address: %s", err) + } + + if err := sdk.VerifyAddressFormat(to); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid recipient address: %s", err) + } + + if !msg.Amount.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) + } + + if !msg.Amount.IsAllPositive() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) + } + + if msg.StartTime > msg.EndTime { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid start time higher than end time") + } + + return nil +} diff --git a/x/qvesting/types/msgs_test.go b/x/qvesting/types/msgs_test.go new file mode 100644 index 000000000..91619a4b4 --- /dev/null +++ b/x/qvesting/types/msgs_test.go @@ -0,0 +1,40 @@ +package types + +import ( + "testing" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/quasarlabs/quasarnode/testutil/sample" + "github.com/stretchr/testify/require" +) + +func TestMsgCreateVestingAccount_ValidateBasic(t *testing.T) { + tests := []struct { + name string + msg MsgCreateVestingAccount + err error + }{ + { + name: "invalid address", + msg: MsgCreateVestingAccount{ + FromAddress: "invalid_address", + }, + err: sdkerrors.ErrInvalidAddress, + }, { + name: "valid address", + msg: MsgCreateVestingAccount{ + FromAddress: sample.AccAddress().String(), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.msg.ValidateBasic() + if tt.err != nil { + require.ErrorIs(t, err, tt.err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/x/qvesting/types/params.go b/x/qvesting/types/params.go new file mode 100644 index 000000000..357196ad6 --- /dev/null +++ b/x/qvesting/types/params.go @@ -0,0 +1,39 @@ +package types + +import ( + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "gopkg.in/yaml.v2" +) + +var _ paramtypes.ParamSet = (*Params)(nil) + +// ParamKeyTable the param key table for launch module +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new Params instance +func NewParams() Params { + return Params{} +} + +// DefaultParams returns a default set of parameters +func DefaultParams() Params { + return NewParams() +} + +// ParamSetPairs get the params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{} +} + +// Validate validates the set of params +func (p Params) Validate() error { + return nil +} + +// String implements the Stringer interface. +func (p Params) String() string { + out, _ := yaml.Marshal(p) + return string(out) +} diff --git a/x/qvesting/types/params.pb.go b/x/qvesting/types/params.pb.go new file mode 100644 index 000000000..295373e46 --- /dev/null +++ b/x/qvesting/types/params.pb.go @@ -0,0 +1,264 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: qvesting/params.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the parameters for the module. +type Params struct { +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_54ed88698b74058b, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Params)(nil), "quasarlabs.quasarnode.qvesting.Params") +} + +func init() { proto.RegisterFile("qvesting/params.proto", fileDescriptor_54ed88698b74058b) } + +var fileDescriptor_54ed88698b74058b = []byte{ + // 156 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2d, 0x2c, 0x4b, 0x2d, + 0x2e, 0xc9, 0xcc, 0x4b, 0xd7, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, + 0xc9, 0x17, 0x92, 0x2b, 0x2c, 0x4d, 0x2c, 0x4e, 0x2c, 0xca, 0x49, 0x4c, 0x2a, 0xd6, 0x83, 0x30, + 0xf3, 0xf2, 0x53, 0x52, 0xf5, 0x60, 0x8a, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x4a, 0xf5, + 0x41, 0x2c, 0x88, 0x2e, 0x25, 0x3e, 0x2e, 0xb6, 0x00, 0xb0, 0x29, 0x56, 0x2c, 0x33, 0x16, 0xc8, + 0x33, 0x38, 0x79, 0x9f, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, + 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x61, 0x7a, + 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0xc2, 0x2a, 0x7d, 0x84, 0x55, 0xfa, + 0x15, 0xfa, 0x70, 0x97, 0x95, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0xed, 0x30, 0x06, 0x04, + 0x00, 0x00, 0xff, 0xff, 0x7d, 0xf4, 0x5d, 0x80, 0xb2, 0x00, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/qvesting/types/query.pb.go b/x/qvesting/types/query.pb.go new file mode 100644 index 000000000..8437c6dfa --- /dev/null +++ b/x/qvesting/types/query.pb.go @@ -0,0 +1,1917 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: qvesting/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types1 "github.com/cosmos/cosmos-sdk/codec/types" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + query "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_2ccd23b8551580b1, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params holds all the parameters of this module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2ccd23b8551580b1, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// QuerySpendableBalancesRequest defines the gRPC request structure for querying +// an account's spendable balances. +type QuerySpendableBalancesRequest struct { + // address is the address to query spendable balances for. + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QuerySpendableBalancesRequest) Reset() { *m = QuerySpendableBalancesRequest{} } +func (m *QuerySpendableBalancesRequest) String() string { return proto.CompactTextString(m) } +func (*QuerySpendableBalancesRequest) ProtoMessage() {} +func (*QuerySpendableBalancesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_2ccd23b8551580b1, []int{2} +} +func (m *QuerySpendableBalancesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySpendableBalancesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySpendableBalancesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QuerySpendableBalancesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySpendableBalancesRequest.Merge(m, src) +} +func (m *QuerySpendableBalancesRequest) XXX_Size() int { + return m.Size() +} +func (m *QuerySpendableBalancesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySpendableBalancesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySpendableBalancesRequest proto.InternalMessageInfo + +// QuerySpendableBalancesResponse defines the gRPC response structure for querying +// an account's spendable balances. +type QuerySpendableBalancesResponse struct { + // balances is the spendable balances of all the coins. + Balances github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=balances,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"balances"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QuerySpendableBalancesResponse) Reset() { *m = QuerySpendableBalancesResponse{} } +func (m *QuerySpendableBalancesResponse) String() string { return proto.CompactTextString(m) } +func (*QuerySpendableBalancesResponse) ProtoMessage() {} +func (*QuerySpendableBalancesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2ccd23b8551580b1, []int{3} +} +func (m *QuerySpendableBalancesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySpendableBalancesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySpendableBalancesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QuerySpendableBalancesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySpendableBalancesResponse.Merge(m, src) +} +func (m *QuerySpendableBalancesResponse) XXX_Size() int { + return m.Size() +} +func (m *QuerySpendableBalancesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySpendableBalancesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySpendableBalancesResponse proto.InternalMessageInfo + +func (m *QuerySpendableBalancesResponse) GetBalances() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Balances + } + return nil +} + +func (m *QuerySpendableBalancesResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryVestingAccountsRequest is the request type for the Query/Accounts RPC method. +type QueryVestingAccountsRequest struct { + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryVestingAccountsRequest) Reset() { *m = QueryVestingAccountsRequest{} } +func (m *QueryVestingAccountsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryVestingAccountsRequest) ProtoMessage() {} +func (*QueryVestingAccountsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_2ccd23b8551580b1, []int{4} +} +func (m *QueryVestingAccountsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryVestingAccountsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryVestingAccountsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryVestingAccountsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryVestingAccountsRequest.Merge(m, src) +} +func (m *QueryVestingAccountsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryVestingAccountsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryVestingAccountsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryVestingAccountsRequest proto.InternalMessageInfo + +func (m *QueryVestingAccountsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryVestingAccountsResponse is the response type for the Query/Accounts RPC method. +type QueryVestingAccountsResponse struct { + // accounts are the existing vesting accounts + Accounts []*types1.Any `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts,omitempty"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryVestingAccountsResponse) Reset() { *m = QueryVestingAccountsResponse{} } +func (m *QueryVestingAccountsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryVestingAccountsResponse) ProtoMessage() {} +func (*QueryVestingAccountsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2ccd23b8551580b1, []int{5} +} +func (m *QueryVestingAccountsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryVestingAccountsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryVestingAccountsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryVestingAccountsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryVestingAccountsResponse.Merge(m, src) +} +func (m *QueryVestingAccountsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryVestingAccountsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryVestingAccountsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryVestingAccountsResponse proto.InternalMessageInfo + +func (m *QueryVestingAccountsResponse) GetAccounts() []*types1.Any { + if m != nil { + return m.Accounts + } + return nil +} + +func (m *QueryVestingAccountsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryVestingLockedSupplyRequest is the request type for the Query/VestingLockedSupply RPC method. +type QueryVestingLockedSupplyRequest struct { + // denom is the coin denom to query locked supply for. + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` +} + +func (m *QueryVestingLockedSupplyRequest) Reset() { *m = QueryVestingLockedSupplyRequest{} } +func (m *QueryVestingLockedSupplyRequest) String() string { return proto.CompactTextString(m) } +func (*QueryVestingLockedSupplyRequest) ProtoMessage() {} +func (*QueryVestingLockedSupplyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_2ccd23b8551580b1, []int{6} +} +func (m *QueryVestingLockedSupplyRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryVestingLockedSupplyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryVestingLockedSupplyRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryVestingLockedSupplyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryVestingLockedSupplyRequest.Merge(m, src) +} +func (m *QueryVestingLockedSupplyRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryVestingLockedSupplyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryVestingLockedSupplyRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryVestingLockedSupplyRequest proto.InternalMessageInfo + +func (m *QueryVestingLockedSupplyRequest) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +// QueryVestingAccountsResponse is the response type for the Query/VestingLockedSupply RPC method. +type QueryVestingLockedSupplyResponse struct { + // amount is the supply of the coin. + Amount types.Coin `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount"` +} + +func (m *QueryVestingLockedSupplyResponse) Reset() { *m = QueryVestingLockedSupplyResponse{} } +func (m *QueryVestingLockedSupplyResponse) String() string { return proto.CompactTextString(m) } +func (*QueryVestingLockedSupplyResponse) ProtoMessage() {} +func (*QueryVestingLockedSupplyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2ccd23b8551580b1, []int{7} +} +func (m *QueryVestingLockedSupplyResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryVestingLockedSupplyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryVestingLockedSupplyResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryVestingLockedSupplyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryVestingLockedSupplyResponse.Merge(m, src) +} +func (m *QueryVestingLockedSupplyResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryVestingLockedSupplyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryVestingLockedSupplyResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryVestingLockedSupplyResponse proto.InternalMessageInfo + +func (m *QueryVestingLockedSupplyResponse) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "quasarlabs.quasarnode.qvesting.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "quasarlabs.quasarnode.qvesting.QueryParamsResponse") + proto.RegisterType((*QuerySpendableBalancesRequest)(nil), "quasarlabs.quasarnode.qvesting.QuerySpendableBalancesRequest") + proto.RegisterType((*QuerySpendableBalancesResponse)(nil), "quasarlabs.quasarnode.qvesting.QuerySpendableBalancesResponse") + proto.RegisterType((*QueryVestingAccountsRequest)(nil), "quasarlabs.quasarnode.qvesting.QueryVestingAccountsRequest") + proto.RegisterType((*QueryVestingAccountsResponse)(nil), "quasarlabs.quasarnode.qvesting.QueryVestingAccountsResponse") + proto.RegisterType((*QueryVestingLockedSupplyRequest)(nil), "quasarlabs.quasarnode.qvesting.QueryVestingLockedSupplyRequest") + proto.RegisterType((*QueryVestingLockedSupplyResponse)(nil), "quasarlabs.quasarnode.qvesting.QueryVestingLockedSupplyResponse") +} + +func init() { proto.RegisterFile("qvesting/query.proto", fileDescriptor_2ccd23b8551580b1) } + +var fileDescriptor_2ccd23b8551580b1 = []byte{ + // 716 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcf, 0x4f, 0x13, 0x4f, + 0x1c, 0xed, 0xf0, 0xfd, 0x52, 0x71, 0x48, 0x34, 0x0e, 0x35, 0x29, 0x2b, 0x6e, 0xc9, 0x1e, 0xb0, + 0x21, 0x61, 0x07, 0x4a, 0x0c, 0x89, 0x02, 0x4a, 0x25, 0x7a, 0xd0, 0x03, 0x96, 0xc4, 0x83, 0x1c, + 0xc8, 0xec, 0xee, 0xb8, 0x6e, 0x68, 0x67, 0xb6, 0x9d, 0x5d, 0x62, 0x43, 0xb8, 0x78, 0x32, 0xf1, + 0x62, 0xe2, 0x3f, 0x00, 0x57, 0x13, 0x6f, 0x9e, 0x3d, 0x13, 0x4f, 0x44, 0x0f, 0x72, 0x52, 0x03, + 0x1e, 0xfc, 0x33, 0x4c, 0x67, 0x66, 0xfb, 0x03, 0x0a, 0x85, 0xc6, 0x53, 0x3b, 0x3f, 0xde, 0xfb, + 0xbc, 0xf7, 0xd9, 0xcf, 0x1b, 0x98, 0xa9, 0x6e, 0x52, 0x11, 0x05, 0xcc, 0xc7, 0xd5, 0x98, 0xd6, + 0xea, 0x76, 0x58, 0xe3, 0x11, 0x47, 0x66, 0x35, 0x26, 0x82, 0xd4, 0xca, 0xc4, 0x11, 0xb6, 0xfa, + 0xcb, 0xb8, 0x47, 0xed, 0xe4, 0xae, 0x91, 0xf1, 0xb9, 0xcf, 0xe5, 0x55, 0xdc, 0xf8, 0xa7, 0x50, + 0xc6, 0x98, 0xcf, 0xb9, 0x5f, 0xa6, 0x98, 0x84, 0x01, 0x26, 0x8c, 0xf1, 0x88, 0x44, 0x01, 0x67, + 0x42, 0x9f, 0x4e, 0xba, 0x5c, 0x54, 0xb8, 0xc0, 0x0e, 0x11, 0x54, 0x15, 0xc3, 0x9b, 0x33, 0x0e, + 0x8d, 0xc8, 0x0c, 0x0e, 0x89, 0x1f, 0x30, 0x79, 0x59, 0xdf, 0xbd, 0xde, 0x54, 0x15, 0x92, 0x1a, + 0xa9, 0x24, 0x14, 0xa3, 0xba, 0x80, 0x5c, 0x39, 0xf1, 0x0b, 0x4c, 0x98, 0x56, 0x6c, 0x98, 0xed, + 0xec, 0x09, 0xaf, 0xcb, 0x83, 0x84, 0x71, 0x54, 0x9d, 0xaf, 0x2b, 0xd1, 0x6a, 0xa1, 0x8e, 0xac, + 0x0c, 0x44, 0x4f, 0x1b, 0x72, 0x56, 0x64, 0xa9, 0x12, 0xad, 0xc6, 0x54, 0x44, 0xd6, 0x1a, 0x1c, + 0xe9, 0xd8, 0x15, 0x21, 0x67, 0x82, 0xa2, 0x65, 0x98, 0x56, 0x92, 0xb2, 0x60, 0x1c, 0xe4, 0x87, + 0x0b, 0x13, 0xf6, 0xd9, 0xad, 0xb2, 0x15, 0xbe, 0xf8, 0xff, 0xde, 0x8f, 0x5c, 0xaa, 0xa4, 0xb1, + 0xd6, 0x5b, 0x00, 0x6f, 0x4a, 0xf6, 0xd5, 0x90, 0x32, 0x8f, 0x38, 0x65, 0x5a, 0x24, 0x65, 0xc2, + 0x5c, 0x9a, 0x94, 0x47, 0x59, 0x78, 0x89, 0x78, 0x5e, 0x8d, 0x0a, 0x55, 0xe8, 0x72, 0x29, 0x59, + 0xa2, 0x87, 0x10, 0xb6, 0xfa, 0x95, 0x1d, 0xd0, 0x2a, 0xb4, 0xa3, 0x86, 0x7d, 0x5b, 0x7d, 0x49, + 0xdd, 0x04, 0x7b, 0x85, 0xf8, 0x54, 0xb3, 0x96, 0xda, 0x90, 0x77, 0x86, 0xde, 0xec, 0xe4, 0x52, + 0x7f, 0x76, 0x72, 0x29, 0xeb, 0x2b, 0x80, 0xe6, 0x69, 0x6a, 0xb4, 0x6d, 0x1f, 0x0e, 0x39, 0x7a, + 0x2f, 0x0b, 0xc6, 0xff, 0xcb, 0x0f, 0x17, 0x46, 0x3b, 0x4a, 0x26, 0xc5, 0x1e, 0xf0, 0x80, 0x15, + 0xa7, 0x1b, 0x5e, 0x3f, 0xfc, 0xcc, 0xe5, 0xfd, 0x20, 0x7a, 0x19, 0x3b, 0xb6, 0xcb, 0x2b, 0xba, + 0xe3, 0xfa, 0x67, 0x4a, 0x78, 0x1b, 0x38, 0xaa, 0x87, 0x54, 0x48, 0x80, 0x28, 0x35, 0xc9, 0xd1, + 0xa3, 0x2e, 0xee, 0x6e, 0xf5, 0x74, 0xa7, 0x54, 0xb6, 0xdb, 0xb3, 0x28, 0xbc, 0x21, 0x3d, 0x3d, + 0x53, 0xdf, 0x61, 0xc9, 0x75, 0x79, 0xcc, 0xa2, 0x66, 0x7f, 0x3b, 0xbb, 0x08, 0xfa, 0xed, 0xa2, + 0xf5, 0x11, 0xc0, 0xb1, 0xee, 0x75, 0x9a, 0x03, 0x33, 0x44, 0xf4, 0x9e, 0xee, 0x5c, 0xc6, 0x56, + 0x63, 0x6c, 0x27, 0x63, 0x6c, 0x2f, 0xb1, 0x7a, 0x11, 0x7d, 0xf9, 0x34, 0x75, 0xa5, 0x93, 0xa4, + 0xd4, 0x44, 0xfe, 0xbb, 0xb6, 0xcc, 0xc1, 0x5c, 0xbb, 0xdc, 0x27, 0xdc, 0xdd, 0xa0, 0xde, 0x6a, + 0x1c, 0x86, 0xe5, 0x7a, 0xd2, 0x9a, 0x0c, 0x1c, 0xf4, 0x28, 0xe3, 0x15, 0x3d, 0x78, 0x6a, 0x61, + 0xad, 0xc1, 0xf1, 0xd3, 0x81, 0xda, 0xeb, 0x1c, 0x4c, 0x93, 0x4a, 0x43, 0xb0, 0x6e, 0xe8, 0x19, + 0x33, 0xa2, 0xf3, 0xa0, 0xae, 0x17, 0x76, 0xd3, 0x70, 0x50, 0xb2, 0xa3, 0x5d, 0x00, 0xd3, 0x2a, + 0x32, 0xa8, 0xd0, 0x2b, 0x5a, 0x27, 0x53, 0x6b, 0xcc, 0x5e, 0x08, 0xa3, 0x64, 0x5b, 0xf6, 0xeb, + 0x6f, 0xbf, 0xdf, 0x0f, 0xe4, 0xd1, 0x04, 0x6e, 0x81, 0x71, 0x0b, 0x8c, 0x8f, 0x3d, 0x46, 0xe8, + 0x00, 0xc0, 0x6b, 0x27, 0xa2, 0x82, 0x16, 0xce, 0x55, 0xfa, 0xb4, 0xc0, 0x1b, 0x8b, 0xfd, 0xc2, + 0xb5, 0x89, 0x65, 0x69, 0x62, 0x11, 0xcd, 0xf7, 0x32, 0x21, 0x12, 0x8a, 0xf5, 0x24, 0x74, 0x78, + 0x4b, 0xbf, 0x2d, 0xdb, 0xe8, 0x33, 0x80, 0x57, 0x8f, 0x4d, 0x32, 0xba, 0x7b, 0x2e, 0x65, 0xdd, + 0x73, 0x66, 0xcc, 0xf7, 0x07, 0xd6, 0xa6, 0xa6, 0xa5, 0xa9, 0x49, 0x94, 0xef, 0x65, 0xaa, 0x19, + 0x94, 0xef, 0x00, 0x8e, 0x74, 0x19, 0x51, 0x74, 0xef, 0x22, 0x3a, 0xba, 0xa4, 0xc2, 0xb8, 0xdf, + 0x3f, 0x81, 0x36, 0xb3, 0x20, 0xcd, 0xcc, 0xa1, 0xdb, 0xbd, 0xcc, 0x94, 0x25, 0x7a, 0x5d, 0x48, + 0x38, 0xde, 0x92, 0xf9, 0xdb, 0x2e, 0x3e, 0xde, 0x3b, 0x34, 0xc1, 0xfe, 0xa1, 0x09, 0x7e, 0x1d, + 0x9a, 0xe0, 0xdd, 0x91, 0x99, 0xda, 0x3f, 0x32, 0x53, 0x07, 0x47, 0x66, 0xea, 0xf9, 0x4c, 0xdb, + 0x3b, 0xdb, 0x9d, 0xfa, 0x55, 0x8b, 0x5c, 0x3e, 0xbb, 0x4e, 0x5a, 0xbe, 0x3d, 0xb3, 0x7f, 0x03, + 0x00, 0x00, 0xff, 0xff, 0x6a, 0x65, 0x05, 0xb0, 0xff, 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Parameters queries the parameters of the module. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // SpendableBalances queries the spenable balance of all coins for a single account. + SpendableBalances(ctx context.Context, in *QuerySpendableBalancesRequest, opts ...grpc.CallOption) (*QuerySpendableBalancesResponse, error) + // VestingAccounts returns all the existing vesting accounts + VestingAccounts(ctx context.Context, in *QueryVestingAccountsRequest, opts ...grpc.CallOption) (*QueryVestingAccountsResponse, error) + // VestingAccounts returns all the existing vesting accounts + VestingLockedSupply(ctx context.Context, in *QueryVestingLockedSupplyRequest, opts ...grpc.CallOption) (*QueryVestingLockedSupplyResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.qvesting.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) SpendableBalances(ctx context.Context, in *QuerySpendableBalancesRequest, opts ...grpc.CallOption) (*QuerySpendableBalancesResponse, error) { + out := new(QuerySpendableBalancesResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.qvesting.Query/SpendableBalances", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) VestingAccounts(ctx context.Context, in *QueryVestingAccountsRequest, opts ...grpc.CallOption) (*QueryVestingAccountsResponse, error) { + out := new(QueryVestingAccountsResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.qvesting.Query/VestingAccounts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) VestingLockedSupply(ctx context.Context, in *QueryVestingLockedSupplyRequest, opts ...grpc.CallOption) (*QueryVestingLockedSupplyResponse, error) { + out := new(QueryVestingLockedSupplyResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.qvesting.Query/VestingLockedSupply", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Parameters queries the parameters of the module. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // SpendableBalances queries the spenable balance of all coins for a single account. + SpendableBalances(context.Context, *QuerySpendableBalancesRequest) (*QuerySpendableBalancesResponse, error) + // VestingAccounts returns all the existing vesting accounts + VestingAccounts(context.Context, *QueryVestingAccountsRequest) (*QueryVestingAccountsResponse, error) + // VestingAccounts returns all the existing vesting accounts + VestingLockedSupply(context.Context, *QueryVestingLockedSupplyRequest) (*QueryVestingLockedSupplyResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (*UnimplementedQueryServer) SpendableBalances(ctx context.Context, req *QuerySpendableBalancesRequest) (*QuerySpendableBalancesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SpendableBalances not implemented") +} +func (*UnimplementedQueryServer) VestingAccounts(ctx context.Context, req *QueryVestingAccountsRequest) (*QueryVestingAccountsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VestingAccounts not implemented") +} +func (*UnimplementedQueryServer) VestingLockedSupply(ctx context.Context, req *QueryVestingLockedSupplyRequest) (*QueryVestingLockedSupplyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VestingLockedSupply not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.qvesting.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_SpendableBalances_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuerySpendableBalancesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).SpendableBalances(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.qvesting.Query/SpendableBalances", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).SpendableBalances(ctx, req.(*QuerySpendableBalancesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_VestingAccounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryVestingAccountsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).VestingAccounts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.qvesting.Query/VestingAccounts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).VestingAccounts(ctx, req.(*QueryVestingAccountsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_VestingLockedSupply_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryVestingLockedSupplyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).VestingLockedSupply(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.qvesting.Query/VestingLockedSupply", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).VestingLockedSupply(ctx, req.(*QueryVestingLockedSupplyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "quasarlabs.quasarnode.qvesting.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "SpendableBalances", + Handler: _Query_SpendableBalances_Handler, + }, + { + MethodName: "VestingAccounts", + Handler: _Query_VestingAccounts_Handler, + }, + { + MethodName: "VestingLockedSupply", + Handler: _Query_VestingLockedSupply_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "qvesting/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QuerySpendableBalancesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QuerySpendableBalancesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySpendableBalancesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QuerySpendableBalancesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QuerySpendableBalancesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySpendableBalancesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Balances) > 0 { + for iNdEx := len(m.Balances) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Balances[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryVestingAccountsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryVestingAccountsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryVestingAccountsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryVestingAccountsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryVestingAccountsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryVestingAccountsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Accounts) > 0 { + for iNdEx := len(m.Accounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Accounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryVestingLockedSupplyRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryVestingLockedSupplyRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryVestingLockedSupplyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryVestingLockedSupplyResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryVestingLockedSupplyResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryVestingLockedSupplyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QuerySpendableBalancesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QuerySpendableBalancesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Balances) > 0 { + for _, e := range m.Balances { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryVestingAccountsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryVestingAccountsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Accounts) > 0 { + for _, e := range m.Accounts { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryVestingLockedSupplyRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryVestingLockedSupplyResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Amount.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuerySpendableBalancesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QuerySpendableBalancesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySpendableBalancesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuerySpendableBalancesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QuerySpendableBalancesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySpendableBalancesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Balances", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Balances = append(m.Balances, types.Coin{}) + if err := m.Balances[len(m.Balances)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryVestingAccountsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryVestingAccountsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryVestingAccountsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryVestingAccountsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryVestingAccountsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryVestingAccountsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Accounts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Accounts = append(m.Accounts, &types1.Any{}) + if err := m.Accounts[len(m.Accounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryVestingLockedSupplyRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryVestingLockedSupplyRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryVestingLockedSupplyRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryVestingLockedSupplyResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryVestingLockedSupplyResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryVestingLockedSupplyResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/qvesting/types/query.pb.gw.go b/x/qvesting/types/query.pb.gw.go new file mode 100644 index 000000000..d90c19d4b --- /dev/null +++ b/x/qvesting/types/query.pb.gw.go @@ -0,0 +1,456 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: qvesting/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_SpendableBalances_0 = &utilities.DoubleArray{Encoding: map[string]int{"address": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_SpendableBalances_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySpendableBalancesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_SpendableBalances_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.SpendableBalances(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_SpendableBalances_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySpendableBalancesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_SpendableBalances_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.SpendableBalances(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_VestingAccounts_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_VestingAccounts_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryVestingAccountsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_VestingAccounts_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.VestingAccounts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_VestingAccounts_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryVestingAccountsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_VestingAccounts_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.VestingAccounts(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_VestingLockedSupply_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryVestingLockedSupplyRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := client.VestingLockedSupply(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_VestingLockedSupply_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryVestingLockedSupplyRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := server.VestingLockedSupply(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_SpendableBalances_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_SpendableBalances_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_SpendableBalances_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_VestingAccounts_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_VestingAccounts_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_VestingAccounts_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_VestingLockedSupply_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_VestingLockedSupply_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_VestingLockedSupply_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_SpendableBalances_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_SpendableBalances_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_SpendableBalances_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_VestingAccounts_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_VestingAccounts_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_VestingAccounts_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_VestingLockedSupply_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_VestingLockedSupply_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_VestingLockedSupply_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"quasarlabs", "quasarnode", "qvesting", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_SpendableBalances_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"quasarlabs", "quasarnode", "qvesting", "spendable_balances", "address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_VestingAccounts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"quasarlabs", "quasarnode", "qvesting", "accounts"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_VestingLockedSupply_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"quasarlabs", "quasarnode", "qvesting", "locked_supply", "denom"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_SpendableBalances_0 = runtime.ForwardResponseMessage + + forward_Query_VestingAccounts_0 = runtime.ForwardResponseMessage + + forward_Query_VestingLockedSupply_0 = runtime.ForwardResponseMessage +) diff --git a/x/qvesting/types/tx.pb.go b/x/qvesting/types/tx.pb.go new file mode 100644 index 000000000..bff685d1c --- /dev/null +++ b/x/qvesting/types/tx.pb.go @@ -0,0 +1,760 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: qvesting/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type MsgCreateVestingAccount struct { + FromAddress string `protobuf:"bytes,1,opt,name=fromAddress,proto3" json:"fromAddress,omitempty"` + ToAddress string `protobuf:"bytes,2,opt,name=toAddress,proto3" json:"toAddress,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` + StartTime int64 `protobuf:"varint,4,opt,name=startTime,proto3" json:"startTime,omitempty"` + EndTime int64 `protobuf:"varint,5,opt,name=endTime,proto3" json:"endTime,omitempty"` +} + +func (m *MsgCreateVestingAccount) Reset() { *m = MsgCreateVestingAccount{} } +func (m *MsgCreateVestingAccount) String() string { return proto.CompactTextString(m) } +func (*MsgCreateVestingAccount) ProtoMessage() {} +func (*MsgCreateVestingAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_36991c782a8b747b, []int{0} +} +func (m *MsgCreateVestingAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateVestingAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateVestingAccount.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateVestingAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateVestingAccount.Merge(m, src) +} +func (m *MsgCreateVestingAccount) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateVestingAccount) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateVestingAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateVestingAccount proto.InternalMessageInfo + +func (m *MsgCreateVestingAccount) GetFromAddress() string { + if m != nil { + return m.FromAddress + } + return "" +} + +func (m *MsgCreateVestingAccount) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *MsgCreateVestingAccount) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Amount + } + return nil +} + +func (m *MsgCreateVestingAccount) GetStartTime() int64 { + if m != nil { + return m.StartTime + } + return 0 +} + +func (m *MsgCreateVestingAccount) GetEndTime() int64 { + if m != nil { + return m.EndTime + } + return 0 +} + +type MsgCreateVestingAccountResponse struct { +} + +func (m *MsgCreateVestingAccountResponse) Reset() { *m = MsgCreateVestingAccountResponse{} } +func (m *MsgCreateVestingAccountResponse) String() string { return proto.CompactTextString(m) } +func (*MsgCreateVestingAccountResponse) ProtoMessage() {} +func (*MsgCreateVestingAccountResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_36991c782a8b747b, []int{1} +} +func (m *MsgCreateVestingAccountResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateVestingAccountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateVestingAccountResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateVestingAccountResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateVestingAccountResponse.Merge(m, src) +} +func (m *MsgCreateVestingAccountResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateVestingAccountResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateVestingAccountResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateVestingAccountResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgCreateVestingAccount)(nil), "quasarlabs.quasarnode.qvesting.MsgCreateVestingAccount") + proto.RegisterType((*MsgCreateVestingAccountResponse)(nil), "quasarlabs.quasarnode.qvesting.MsgCreateVestingAccountResponse") +} + +func init() { proto.RegisterFile("qvesting/tx.proto", fileDescriptor_36991c782a8b747b) } + +var fileDescriptor_36991c782a8b747b = []byte{ + // 369 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0xb1, 0x4e, 0xe3, 0x40, + 0x10, 0xf5, 0x9e, 0x73, 0x39, 0x65, 0x53, 0x9d, 0x15, 0xe9, 0x7c, 0xd1, 0x69, 0xed, 0x4b, 0xe5, + 0x86, 0x5d, 0x12, 0x0a, 0x24, 0x1a, 0x94, 0xa4, 0x44, 0x69, 0x2c, 0x44, 0x41, 0xb7, 0xb6, 0x17, + 0x63, 0x81, 0xbd, 0x89, 0x67, 0x13, 0x85, 0xbf, 0x48, 0x49, 0x49, 0xcd, 0x97, 0xa4, 0x4c, 0x49, + 0x05, 0x28, 0x69, 0xf8, 0x08, 0x0a, 0x64, 0x3b, 0x96, 0x53, 0x10, 0x0a, 0xaa, 0x9d, 0x7d, 0x6f, + 0x67, 0xe6, 0xcd, 0xdb, 0xc1, 0xbf, 0x27, 0x33, 0x01, 0x2a, 0x4a, 0x42, 0xa6, 0xe6, 0x74, 0x9c, + 0x4a, 0x25, 0x0d, 0x32, 0x99, 0x72, 0xe0, 0xe9, 0x2d, 0xf7, 0x80, 0x16, 0x61, 0x22, 0x03, 0x41, + 0xcb, 0x87, 0x6d, 0xe2, 0x4b, 0x88, 0x25, 0x30, 0x8f, 0x83, 0x60, 0xb3, 0xae, 0x27, 0x14, 0xef, + 0x32, 0x5f, 0x46, 0x49, 0x91, 0xdf, 0x6e, 0x85, 0x32, 0x94, 0x79, 0xc8, 0xb2, 0xa8, 0x40, 0x3b, + 0xef, 0x08, 0xff, 0x19, 0x41, 0x38, 0x4c, 0x05, 0x57, 0xe2, 0xa2, 0x28, 0xd5, 0xf7, 0x7d, 0x39, + 0x4d, 0x94, 0x61, 0xe3, 0xe6, 0x55, 0x2a, 0xe3, 0x7e, 0x10, 0xa4, 0x02, 0xc0, 0x44, 0x36, 0x72, + 0x1a, 0xee, 0x2e, 0x64, 0xfc, 0xc3, 0x0d, 0x25, 0x4b, 0xfe, 0x47, 0xce, 0x57, 0x80, 0xe1, 0xe3, + 0x3a, 0x8f, 0xb3, 0x4a, 0xa6, 0x6e, 0xeb, 0x4e, 0xb3, 0xf7, 0x97, 0x16, 0x12, 0x69, 0x26, 0x91, + 0x6e, 0x25, 0xd2, 0xa1, 0x8c, 0x92, 0xc1, 0xe1, 0xf2, 0xd9, 0xd2, 0x1e, 0x5f, 0x2c, 0x27, 0x8c, + 0xd4, 0xf5, 0xd4, 0xa3, 0xbe, 0x8c, 0xd9, 0x76, 0x9e, 0xe2, 0x38, 0x80, 0xe0, 0x86, 0xa9, 0xbb, + 0xb1, 0x80, 0x3c, 0x01, 0xdc, 0x6d, 0xe9, 0x4c, 0x02, 0x28, 0x9e, 0xaa, 0xf3, 0x28, 0x16, 0x66, + 0xcd, 0x46, 0x8e, 0xee, 0x56, 0x80, 0x61, 0xe2, 0x5f, 0x22, 0x09, 0x72, 0xee, 0x67, 0xce, 0x95, + 0xd7, 0x93, 0xda, 0xdb, 0x83, 0x85, 0x3a, 0xff, 0xb1, 0xb5, 0x67, 0x7a, 0x57, 0xc0, 0x58, 0x26, + 0x20, 0x7a, 0xf7, 0x08, 0xeb, 0x23, 0x08, 0x8d, 0x05, 0xc2, 0xad, 0x4f, 0x6d, 0x3a, 0xa6, 0x5f, + 0xff, 0x0c, 0xdd, 0xd3, 0xa1, 0x7d, 0xfa, 0xcd, 0xc4, 0x52, 0xda, 0xe0, 0x6c, 0xb9, 0x26, 0x68, + 0xb5, 0x26, 0xe8, 0x75, 0x4d, 0xd0, 0x62, 0x43, 0xb4, 0xd5, 0x86, 0x68, 0x4f, 0x1b, 0xa2, 0x5d, + 0x76, 0x77, 0x7c, 0xac, 0x9a, 0xb0, 0xaa, 0x09, 0x9b, 0xb3, 0x6a, 0xc5, 0x32, 0x5b, 0xbd, 0x7a, + 0xbe, 0x10, 0x47, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x5d, 0x3c, 0xec, 0x7b, 0x02, 0x00, + 0x00, +} + +func (this *MsgCreateVestingAccount) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgCreateVestingAccount) + if !ok { + that2, ok := that.(MsgCreateVestingAccount) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.FromAddress != that1.FromAddress { + return false + } + if this.ToAddress != that1.ToAddress { + return false + } + if len(this.Amount) != len(that1.Amount) { + return false + } + for i := range this.Amount { + if !this.Amount[i].Equal(&that1.Amount[i]) { + return false + } + } + if this.StartTime != that1.StartTime { + return false + } + if this.EndTime != that1.EndTime { + return false + } + return true +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + CreateVestingAccount(ctx context.Context, in *MsgCreateVestingAccount, opts ...grpc.CallOption) (*MsgCreateVestingAccountResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) CreateVestingAccount(ctx context.Context, in *MsgCreateVestingAccount, opts ...grpc.CallOption) (*MsgCreateVestingAccountResponse, error) { + out := new(MsgCreateVestingAccountResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.qvesting.Msg/CreateVestingAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + CreateVestingAccount(context.Context, *MsgCreateVestingAccount) (*MsgCreateVestingAccountResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) CreateVestingAccount(ctx context.Context, req *MsgCreateVestingAccount) (*MsgCreateVestingAccountResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateVestingAccount not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_CreateVestingAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgCreateVestingAccount) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).CreateVestingAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.qvesting.Msg/CreateVestingAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).CreateVestingAccount(ctx, req.(*MsgCreateVestingAccount)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "quasarlabs.quasarnode.qvesting.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateVestingAccount", + Handler: _Msg_CreateVestingAccount_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "qvesting/tx.proto", +} + +func (m *MsgCreateVestingAccount) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgCreateVestingAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.EndTime != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.EndTime)) + i-- + dAtA[i] = 0x28 + } + if m.StartTime != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.StartTime)) + i-- + dAtA[i] = 0x20 + } + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.FromAddress) > 0 { + i -= len(m.FromAddress) + copy(dAtA[i:], m.FromAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.FromAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgCreateVestingAccountResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgCreateVestingAccountResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateVestingAccountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgCreateVestingAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FromAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + if m.StartTime != 0 { + n += 1 + sovTx(uint64(m.StartTime)) + } + if m.EndTime != 0 { + n += 1 + sovTx(uint64(m.EndTime)) + } + return n +} + +func (m *MsgCreateVestingAccountResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgCreateVestingAccount) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgCreateVestingAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreateVestingAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FromAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + m.StartTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) + } + m.EndTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgCreateVestingAccountResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgCreateVestingAccountResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreateVestingAccountResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/qvesting/types/types.go b/x/qvesting/types/types.go new file mode 100644 index 000000000..ab1254f4c --- /dev/null +++ b/x/qvesting/types/types.go @@ -0,0 +1 @@ +package types diff --git a/x/tokenfactory/README.md b/x/tokenfactory/README.md new file mode 100644 index 000000000..51cc57f17 --- /dev/null +++ b/x/tokenfactory/README.md @@ -0,0 +1,193 @@ +# Token Factory + +We have taken most of the source code from from the osmosis repository for the x/tokenfactory module. + +The tokenfactory module allows any account to create a new token with +the name `factory/{creator address}/{subdenom}`. Because tokens are +namespaced by creator address, this allows token minting to be +permissionless, due to not needing to resolve name collisions. A single +account can create multiple denoms, by providing a unique subdenom for each +created denom. Once a denom is created, the original creator is given +"admin" privileges over the asset. This allows them to: + +- Mint their denom to any account +- Burn their denom from any account +- Create a transfer of their denom between any two accounts +- Change the admin. In the future, more admin capabilities may be added. Admins + can choose to share admin privileges with other accounts using the authz + module. The `ChangeAdmin` functionality, allows changing the master admin + account, or even setting it to `""`, meaning no account has admin privileges + of the asset. + +## Messages + +### CreateDenom + +Creates a denom of `factory/{creator address}/{subdenom}` given the denom creator +address and the subdenom. Subdenoms can contain `[a-zA-Z0-9./]`. + +```go +message MsgCreateDenom { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + string subdenom = 2 [ (gogoproto.moretags) = "yaml:\"subdenom\"" ]; +} +``` + +**State Modifications:** + +- Fund community pool with the denom creation fee from the creator address, set + in `Params`. +- Set `DenomMetaData` via bank keeper. +- Set `AuthorityMetadata` for the given denom to store the admin for the created + denom `factory/{creator address}/{subdenom}`. Admin is automatically set as the + Msg sender. +- Add denom to the `CreatorPrefixStore`, where a state of denoms created per + creator is kept. + +### Mint + +Minting of a specific denom is only allowed for the current admin. +Note, the current admin is defaulted to the creator of the denom. + +```go +message MsgMint { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.base.v1beta1.Coin amount = 2 [ + (gogoproto.moretags) = "yaml:\"amount\"", + (gogoproto.nullable) = false + ]; +} +``` + +**State Modifications:** + +- Safety check the following + - Check that the denom minting is created via `tokenfactory` module + - Check that the sender of the message is the admin of the denom +- Mint designated amount of tokens for the denom via `bank` module + +### Burn + +Burning of a specific denom is only allowed for the current admin. +Note, the current admin is defaulted to the creator of the denom. + +```go +message MsgBurn { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.base.v1beta1.Coin amount = 2 [ + (gogoproto.moretags) = "yaml:\"amount\"", + (gogoproto.nullable) = false + ]; +} +``` + +**State Modifications:** + +- Saftey check the following + - Check that the denom minting is created via `tokenfactory` module + - Check that the sender of the message is the admin of the denom +- Burn designated amount of tokens for the denom via `bank` module + +### ChangeAdmin + +Change the admin of a denom. Note, this is only allowed to be called by the current admin of the denom. + +```go +message MsgChangeAdmin { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + string denom = 2 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; + string newAdmin = 3 [ (gogoproto.moretags) = "yaml:\"new_admin\"" ]; +} +``` + +### SetDenomMetadata + +Setting of metadata for a specific denom is only allowed for the admin of the denom. +It allows the overwriting of the denom metadata in the bank module. + +```go +message MsgChangeAdmin { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.bank.v1beta1.Metadata metadata = 2 [ (gogoproto.moretags) = "yaml:\"metadata\"", (gogoproto.nullable) = false ]; +} +``` + +**State Modifications:** + +- Check that sender of the message is the admin of denom +- Modify `AuthorityMetadata` state entry to change the admin of the denom + +## Expectations from the chain + +The chain's bech32 prefix for addresses can be at most 16 characters long. + +This comes from denoms having a 128 byte maximum length, enforced from the SDK, +and us setting longest_subdenom to be 44 bytes. + +A token factory token's denom is: `factory/{creator address}/{subdenom}` + +Splitting up into sub-components, this has: + +- `len(factory) = 7` +- `2 * len("/") = 2` +- `len(longest_subdenom)` +- `len(creator_address) = len(bech32(longest_addr_length, chain_addr_prefix))`. + +Longest addr length at the moment is `32 bytes`. Due to SDK error correction +settings, this means `len(bech32(32, chain_addr_prefix)) = len(chain_addr_prefix) + 1 + 58`. +Adding this all, we have a total length constraint of `128 = 7 + 2 + len(longest_subdenom) + len(longest_chain_addr_prefix) + 1 + 58`. +Therefore `len(longest_subdenom) + len(longest_chain_addr_prefix) = 128 - (7 + 2 + 1 + 58) = 60`. + +The choice between how we standardized the split these 60 bytes between maxes +from longest_subdenom and longest_chain_addr_prefix is somewhat arbitrary. +Considerations going into this: + +- Per [BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32) + the technically longest HRP for a 32 byte address ('data field') is 31 bytes. + (Comes from encode(data) = 59 bytes, and max length = 90 bytes) +- subdenom should be at least 32 bytes so hashes can go into it +- longer subdenoms are very helpful for creating human readable denoms +- chain addresses should prefer being smaller. The longest HRP in cosmos to date is 11 bytes. (`persistence`) + +For explicitness, its currently set to `len(longest_subdenom) = 44` and `len(longest_chain_addr_prefix) = 16`. + +Please note, if the SDK increases the maximum length of a denom from 128 bytes, +these caps should increase. + +So please don't make code rely on these max lengths for parsing. + +# Examples +To create a new token, use the create-denom command from the tokenfactory module. The following example uses the address osmo1c584m4lq25h83yp6ag8hh4htjr92d954vklzja from mylocalwallet as the default admin for the new token. + +## Creating a token +To create a new token we can use the create-denom command. + +```sh +quasarnoded tx tokenfactory create-denom ufoo --keyring-backend=test --from alice --keyring-backend test --home ~/.quasarnode --chain-id quasar --node tcp://localhost:26659 +quasarnoded q tokenfactory denom-authority-metadata factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/ufoo --node tcp://localhost:26659 + +``` + +## Mint a new token +Once a new token is created, it can be minted using the mint command in the tokenfactory module. Note that the complete tokenfactory address, in the format of factory/{creator address}/{subdenom}, must be used to mint the token. + +```sh +quasarnoded tx tokenfactory mint 100000000000factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/ufoo --keyring-backend=test --from alice --keyring-backend test --home ~/.quasarnode --chain-id quasar --node tcp://localhost:26659 +``` + +## Checking Token metadata +To view a token's metadata, use the denom-metadata command in the bank module. The following example queries the metadata for the token factory/osmo1c584m4lq25h83yp6ag8hh4htjr92d954vklzja/ufoo: + +```sh +quasarnoded query bank denom-metadata --denom factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/ufoo +quasarnoded q tokenfactory denoms-from-creator quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node tcp://localhost:26659 +quasarnoded q tokenfactory denom-authority-metadata factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/ufoo --node tcp://localhost:26659 + +``` + +## Check the tokens created by an account +To see a list of tokens created by a specific account, use the denoms-from-creator command in the tokenfactory module. The following example shows tokens created by the account osmo1c584m4lq25h83yp6ag8hh4htjr92d954vklzja: + +```sh +quasarnoded query tokenfactory denoms-from-creator quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec +``` diff --git a/x/tokenfactory/bindings/custom_msg_test.go b/x/tokenfactory/bindings/custom_msg_test.go new file mode 100644 index 000000000..70110f66f --- /dev/null +++ b/x/tokenfactory/bindings/custom_msg_test.go @@ -0,0 +1 @@ +package bindings_test diff --git a/x/tokenfactory/bindings/custom_query_test.go b/x/tokenfactory/bindings/custom_query_test.go new file mode 100644 index 000000000..fea175c1c --- /dev/null +++ b/x/tokenfactory/bindings/custom_query_test.go @@ -0,0 +1,76 @@ +package bindings_test + +/* +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/quasarlabs/quasarnode/app" + bindings "github.com/quasarlabs/quasarnode/x/tokenfactory/bindings/types" +) + +func TestQueryFullDenom(t *testing.T) { + actor := RandomAccountAddress() + tokenz, ctx := SetupCustomApp(t, actor) + + reflect := instantiateReflectContract(t, ctx, tokenz, actor) + require.NotEmpty(t, reflect) + + // query full denom + query := bindings.TokenQuery{ + FullDenom: &bindings.FullDenom{ + CreatorAddr: reflect.String(), + Subdenom: "ustart", + }, + } + resp := bindings.FullDenomResponse{} + queryCustom(t, ctx, tokenz, reflect, query, &resp) + + expected := fmt.Sprintf("factory/%s/ustart", reflect.String()) + require.EqualValues(t, expected, resp.Denom) +} + +type ReflectQuery struct { + Chain *ChainRequest `json:"chain,omitempty"` +} + +type ChainRequest struct { + Request wasmvmtypes.QueryRequest `json:"request"` +} + +type ChainResponse struct { + Data []byte `json:"data"` +} + +func queryCustom(t *testing.T, ctx sdk.Context, tokenz *app.TokenApp, contract sdk.AccAddress, request bindings.TokenQuery, response interface{}) { + wrapped := bindings.TokenFactoryQuery{ + Token: &request, + } + msgBz, err := json.Marshal(wrapped) + require.NoError(t, err) + fmt.Println(string(msgBz)) + + query := ReflectQuery{ + Chain: &ChainRequest{ + Request: wasmvmtypes.QueryRequest{Custom: msgBz}, + }, + } + queryBz, err := json.Marshal(query) + require.NoError(t, err) + fmt.Println(string(queryBz)) + + resBz, err := tokenz.WasmKeeper.QuerySmart(ctx, contract, queryBz) + require.NoError(t, err) + var resp ChainResponse + err = json.Unmarshal(resBz, &resp) + require.NoError(t, err) + err = json.Unmarshal(resp.Data, response) + require.NoError(t, err) +} +*/ diff --git a/x/tokenfactory/bindings/helpers_test.go b/x/tokenfactory/bindings/helpers_test.go new file mode 100644 index 000000000..4044f9468 --- /dev/null +++ b/x/tokenfactory/bindings/helpers_test.go @@ -0,0 +1,94 @@ +package bindings_test + +/* +import ( + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/quasarlabs/quasarnode/app" +) + +func CreateTestInput() (*app.TokenApp, sdk.Context) { + osmosis := app.Setup(false) + ctx := osmosis.BaseApp.NewContext(false, tmproto.Header{Height: 1, ChainID: "osmosis-1", Time: time.Now().UTC()}) + return osmosis, ctx +} + +func FundAccount(t *testing.T, ctx sdk.Context, osmosis *app.TokenApp, acct sdk.AccAddress) { + err := simapp.FundAccount(osmosis.BankKeeper, ctx, acct, sdk.NewCoins( + sdk.NewCoin("uosmo", sdk.NewInt(10000000000)), + )) + require.NoError(t, err) +} + +// we need to make this deterministic (same every test run), as content might affect gas costs +func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) { + key := ed25519.GenPrivKey() + pub := key.PubKey() + addr := sdk.AccAddress(pub.Address()) + return key, pub, addr +} + +func RandomAccountAddress() sdk.AccAddress { + _, _, addr := keyPubAddr() + return addr +} + +func RandomBech32AccountAddress() string { + return RandomAccountAddress().String() +} + +func storeReflectCode(t *testing.T, ctx sdk.Context, tokenz *app.TokenApp, addr sdk.AccAddress) uint64 { + wasmCode, err := os.ReadFile("./testdata/token_reflect.wasm") + require.NoError(t, err) + + contractKeeper := keeper.NewDefaultPermissionKeeper(tokenz.WasmKeeper) + codeID, _, err := contractKeeper.Create(ctx, addr, wasmCode, nil) + require.NoError(t, err) + + return codeID +} + +func instantiateReflectContract(t *testing.T, ctx sdk.Context, tokenz *app.TokenApp, funder sdk.AccAddress) sdk.AccAddress { + initMsgBz := []byte("{}") + contractKeeper := keeper.NewDefaultPermissionKeeper(tokenz.WasmKeeper) + codeID := uint64(1) + addr, _, err := contractKeeper.Instantiate(ctx, codeID, funder, funder, initMsgBz, "demo contract", nil) + require.NoError(t, err) + + return addr +} + +func fundAccount(t *testing.T, ctx sdk.Context, tokenz *app.TokenApp, addr sdk.AccAddress, coins sdk.Coins) { + err := simapp.FundAccount( + tokenz.BankKeeper, + ctx, + addr, + coins, + ) + require.NoError(t, err) +} + +func SetupCustomApp(t *testing.T, addr sdk.AccAddress) (*app.TokenApp, sdk.Context) { + tokenz, ctx := CreateTestInput() + wasmKeeper := tokenz.WasmKeeper + + storeReflectCode(t, ctx, tokenz, addr) + + cInfo := wasmKeeper.GetCodeInfo(ctx, 1) + require.NotNil(t, cInfo) + + return tokenz, ctx +} +*/ diff --git a/x/tokenfactory/bindings/message_plugin.go b/x/tokenfactory/bindings/message_plugin.go new file mode 100644 index 000000000..522abb5cb --- /dev/null +++ b/x/tokenfactory/bindings/message_plugin.go @@ -0,0 +1,332 @@ +package bindings + +import ( + "encoding/json" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + bindingstypes "github.com/quasarlabs/quasarnode/x/tokenfactory/bindings/types" + tokenfactorykeeper "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" + tokenfactorytypes "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +// CustomMessageDecorator returns decorator for custom CosmWasm bindings messages +func CustomMessageDecorator(bank *bankkeeper.BaseKeeper, tokenFactory *tokenfactorykeeper.Keeper) func(wasmkeeper.Messenger) wasmkeeper.Messenger { + return func(old wasmkeeper.Messenger) wasmkeeper.Messenger { + return &CustomMessenger{ + wrapped: old, + bank: bank, + tokenFactory: tokenFactory, + } + } +} + +type CustomMessenger struct { + wrapped wasmkeeper.Messenger + bank *bankkeeper.BaseKeeper + tokenFactory *tokenfactorykeeper.Keeper +} + +var _ wasmkeeper.Messenger = (*CustomMessenger)(nil) + +// DispatchMsg executes on the contractMsg. This is used to call tx related operations on the token factory module. Here it will be direct keeper call +// through the CustomMessages struct which is made to implement the wasmkeeper.Messenger. This struct has token factory keeper so has all the capabilities of +// the token factory. It also has wasm keeper so after doing its job on token factory, it can call back the wasm keeper function for providing the token factory +// function responses. +func (m *CustomMessenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { + if msg.Custom != nil { + // only handle the happy path where this is really creating / minting / swapping ... + // leave everything else for the wrapped version + var contractMsg bindingstypes.TokenFactoryMsg + if err := json.Unmarshal(msg.Custom, &contractMsg); err != nil { + return nil, nil, sdkerrors.Wrap(err, "token factory msg") + } + if contractMsg.Token == nil { + return nil, nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "nil token field") + } + tokenMsg := contractMsg.Token + + if tokenMsg.CreateDenom != nil { + return m.createDenom(ctx, contractAddr, tokenMsg.CreateDenom) + } + if tokenMsg.MintTokens != nil { + return m.mintTokens(ctx, contractAddr, tokenMsg.MintTokens) + } + if tokenMsg.ChangeAdmin != nil { + return m.changeAdmin(ctx, contractAddr, tokenMsg.ChangeAdmin) + } + if tokenMsg.BurnTokens != nil { + return m.burnTokens(ctx, contractAddr, tokenMsg.BurnTokens) + } + if tokenMsg.SetMetadata != nil { + return m.setMetadata(ctx, contractAddr, tokenMsg.SetMetadata) + } + + } + return m.wrapped.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) +} + +// createDenom creates a new token denom +func (m *CustomMessenger) createDenom(ctx sdk.Context, contractAddr sdk.AccAddress, createDenom *bindingstypes.CreateDenom) ([]sdk.Event, [][]byte, error) { + bz, err := PerformCreateDenom(m.tokenFactory, m.bank, ctx, contractAddr, createDenom) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "perform create denom") + } + // TODO: double check how this is all encoded to the contract + return nil, [][]byte{bz}, nil +} + +// PerformCreateDenom is used with createDenom to create a token denom; validates the msgCreateDenom. +func PerformCreateDenom(f *tokenfactorykeeper.Keeper, b *bankkeeper.BaseKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, createDenom *bindingstypes.CreateDenom) ([]byte, error) { + if createDenom == nil { + return nil, wasmvmtypes.InvalidRequest{Err: "create denom null create denom"} + } + + msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) + + msgCreateDenom := tokenfactorytypes.NewMsgCreateDenom(contractAddr.String(), createDenom.Subdenom) + + if err := msgCreateDenom.ValidateBasic(); err != nil { + return nil, sdkerrors.Wrap(err, "failed validating MsgCreateDenom") + } + + // Create denom + resp, err := msgServer.CreateDenom( + sdk.WrapSDKContext(ctx), + msgCreateDenom, + ) + if err != nil { + return nil, sdkerrors.Wrap(err, "creating denom") + } + + if createDenom.Metadata != nil { + newDenom := resp.NewTokenDenom + err := PerformSetMetadata(f, b, ctx, contractAddr, newDenom, *createDenom.Metadata) + if err != nil { + return nil, sdkerrors.Wrap(err, "setting metadata") + } + } + + return resp.Marshal() +} + +// mintTokens mints tokens of a specified denom to an address. +func (m *CustomMessenger) mintTokens(ctx sdk.Context, contractAddr sdk.AccAddress, mint *bindingstypes.MintTokens) ([]sdk.Event, [][]byte, error) { + err := PerformMint(m.tokenFactory, m.bank, ctx, contractAddr, mint) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "perform mint") + } + return nil, nil, nil +} + +// PerformMint used with mintTokens to validate the mint message and mint through token factory. +func PerformMint(f *tokenfactorykeeper.Keeper, b *bankkeeper.BaseKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, mint *bindingstypes.MintTokens) error { + if mint == nil { + return wasmvmtypes.InvalidRequest{Err: "mint token null mint"} + } + rcpt, err := parseAddress(mint.MintToAddress) + if err != nil { + return err + } + + coin := sdk.Coin{Denom: mint.Denom, Amount: mint.Amount} + sdkMsg := tokenfactorytypes.NewMsgMint(contractAddr.String(), coin) + + if err = sdkMsg.ValidateBasic(); err != nil { + return err + } + + // Mint through token factory / message server + msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) + _, err = msgServer.Mint(sdk.WrapSDKContext(ctx), sdkMsg) + if err != nil { + return sdkerrors.Wrap(err, "minting coins from message") + } + + if b.BlockedAddr(rcpt) { + return sdkerrors.Wrapf(err, "minting coins to blocked address %s", rcpt.String()) + } + + err = b.SendCoins(ctx, contractAddr, rcpt, sdk.NewCoins(coin)) + if err != nil { + return sdkerrors.Wrap(err, "sending newly minted coins from message") + } + return nil +} + +// changeAdmin changes the admin. +func (m *CustomMessenger) changeAdmin(ctx sdk.Context, contractAddr sdk.AccAddress, changeAdmin *bindingstypes.ChangeAdmin) ([]sdk.Event, [][]byte, error) { + err := ChangeAdmin(m.tokenFactory, ctx, contractAddr, changeAdmin) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "failed to change admin") + } + return nil, nil, nil +} + +// ChangeAdmin is used with changeAdmin to validate changeAdmin messages and to dispatch. +func ChangeAdmin(f *tokenfactorykeeper.Keeper, ctx sdk.Context, contractAddr sdk.AccAddress, changeAdmin *bindingstypes.ChangeAdmin) error { + if changeAdmin == nil { + return wasmvmtypes.InvalidRequest{Err: "changeAdmin is nil"} + } + newAdminAddr, err := parseAddress(changeAdmin.NewAdminAddress) + if err != nil { + return err + } + + changeAdminMsg := tokenfactorytypes.NewMsgChangeAdmin(contractAddr.String(), changeAdmin.Denom, newAdminAddr.String()) + if err := changeAdminMsg.ValidateBasic(); err != nil { + return err + } + + msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) + _, err = msgServer.ChangeAdmin(sdk.WrapSDKContext(ctx), changeAdminMsg) + if err != nil { + return sdkerrors.Wrap(err, "failed changing admin from message") + } + return nil +} + +// burnTokens burns tokens. +func (m *CustomMessenger) burnTokens(ctx sdk.Context, contractAddr sdk.AccAddress, burn *bindingstypes.BurnTokens) ([]sdk.Event, [][]byte, error) { + err := PerformBurn(m.tokenFactory, ctx, contractAddr, burn) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "perform burn") + } + return nil, nil, nil +} + +// PerformBurn performs token burning after validating tokenBurn message. +func PerformBurn(f *tokenfactorykeeper.Keeper, ctx sdk.Context, contractAddr sdk.AccAddress, burn *bindingstypes.BurnTokens) error { + if burn == nil { + return wasmvmtypes.InvalidRequest{Err: "burn token null mint"} + } + + coin := sdk.Coin{Denom: burn.Denom, Amount: burn.Amount} + sdkMsg := tokenfactorytypes.NewMsgBurn(contractAddr.String(), coin) + /* // TODO - Considerations for future. It is implemented in juno + if burn.BurnFromAddress != "" { + sdkMsg = tokenfactorytypes.NewMsgBurnFrom(contractAddr.String(), coin, burn.BurnFromAddress) + } + */ + + if err := sdkMsg.ValidateBasic(); err != nil { + return err + } + + // Burn through token factory / message server + msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) + _, err := msgServer.Burn(sdk.WrapSDKContext(ctx), sdkMsg) + if err != nil { + return sdkerrors.Wrap(err, "burning coins from message") + } + return nil +} + +// createDenom creates a new token denom +func (m *CustomMessenger) setMetadata(ctx sdk.Context, contractAddr sdk.AccAddress, setMetadata *bindingstypes.SetMetadata) ([]sdk.Event, [][]byte, error) { + err := PerformSetMetadata(m.tokenFactory, m.bank, ctx, contractAddr, setMetadata.Denom, setMetadata.Metadata) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "perform create denom") + } + return nil, nil, nil +} + +// PerformSetMetadata is used with setMetadata to add new metadata +// It also is called inside CreateDenom if optional metadata field is set +func PerformSetMetadata(f *tokenfactorykeeper.Keeper, b *bankkeeper.BaseKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, denom string, metadata bindingstypes.Metadata) error { + // ensure contract address is admin of denom + auth, err := f.GetAuthorityMetadata(ctx, denom) + if err != nil { + return err + } + if auth.Admin != contractAddr.String() { + return wasmvmtypes.InvalidRequest{Err: "only admin can set metadata"} + } + + // ensure we are setting proper denom metadata (bank uses Base field, fill it if missing) + if metadata.Base == "" { + metadata.Base = denom + } else if metadata.Base != denom { + // this is the key that we set + return wasmvmtypes.InvalidRequest{Err: "Base must be the same as denom"} + } + + // Create and validate the metadata + bankMetadata := WasmMetadataToSdk(metadata) + if err := bankMetadata.Validate(); err != nil { + return err + } + + b.SetDenomMetaData(ctx, bankMetadata) + return nil +} + +// GetFullDenom is a function, not method, so the message_plugin can use it +func GetFullDenom(contract string, subDenom string) (string, error) { + // Address validation + if _, err := parseAddress(contract); err != nil { + return "", err + } + fullDenom, err := tokenfactorytypes.GetTokenDenom(contract, subDenom) + if err != nil { + return "", sdkerrors.Wrap(err, "validate sub-denom") + } + + return fullDenom, nil +} + +// parseAddress parses address from bech32 string and verifies its format. +func parseAddress(addr string) (sdk.AccAddress, error) { + parsed, err := sdk.AccAddressFromBech32(addr) + if err != nil { + return nil, sdkerrors.Wrap(err, "address from bech32") + } + err = sdk.VerifyAddressFormat(parsed) + if err != nil { + return nil, sdkerrors.Wrap(err, "verify address format") + } + return parsed, nil +} + +func WasmMetadataToSdk(metadata bindingstypes.Metadata) banktypes.Metadata { + denoms := []*banktypes.DenomUnit{} + for _, unit := range metadata.DenomUnits { + denoms = append(denoms, &banktypes.DenomUnit{ + Denom: unit.Denom, + Exponent: unit.Exponent, + Aliases: unit.Aliases, + }) + } + return banktypes.Metadata{ + Description: metadata.Description, + Display: metadata.Display, + Base: metadata.Base, + Name: metadata.Name, + Symbol: metadata.Symbol, + DenomUnits: denoms, + } +} + +func SdkMetadataToWasm(metadata banktypes.Metadata) *bindingstypes.Metadata { + denoms := []bindingstypes.DenomUnit{} + for _, unit := range metadata.DenomUnits { + denoms = append(denoms, bindingstypes.DenomUnit{ + Denom: unit.Denom, + Exponent: unit.Exponent, + Aliases: unit.Aliases, + }) + } + return &bindingstypes.Metadata{ + Description: metadata.Description, + Display: metadata.Display, + Base: metadata.Base, + Name: metadata.Name, + Symbol: metadata.Symbol, + DenomUnits: denoms, + } +} diff --git a/x/tokenfactory/bindings/queries.go b/x/tokenfactory/bindings/queries.go new file mode 100644 index 000000000..185dd922d --- /dev/null +++ b/x/tokenfactory/bindings/queries.go @@ -0,0 +1,61 @@ +package bindings + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + + bindingstypes "github.com/quasarlabs/quasarnode/x/tokenfactory/bindings/types" + tokenfactorykeeper "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" +) + +// QueryPlugin represents a plugin that provides query functionalities related +// to banking and token factory modules. +type QueryPlugin struct { + bankKeeper *bankkeeper.BaseKeeper + tokenFactoryKeeper *tokenfactorykeeper.Keeper +} + +// NewQueryPlugin returns a reference to a new QueryPlugin object. +func NewQueryPlugin(b *bankkeeper.BaseKeeper, tfk *tokenfactorykeeper.Keeper) *QueryPlugin { + return &QueryPlugin{ + bankKeeper: b, + tokenFactoryKeeper: tfk, + } +} + +// GetDenomAdmin is a query to get denom admin. +func (qp QueryPlugin) GetDenomAdmin(ctx sdk.Context, denom string) (*bindingstypes.AdminResponse, error) { + metadata, err := qp.tokenFactoryKeeper.GetAuthorityMetadata(ctx, denom) + if err != nil { + return nil, fmt.Errorf("failed to get admin for denom: %s", denom) + } + return &bindingstypes.AdminResponse{Admin: metadata.Admin}, nil +} + +// GetDenomsByCreator is a query to get list of denom strings created by a creator. +func (qp QueryPlugin) GetDenomsByCreator(ctx sdk.Context, creator string) (*bindingstypes.DenomsByCreatorResponse, error) { + // TODO: validate creator address + denoms := qp.tokenFactoryKeeper.GetDenomsFromCreator(ctx, creator) + return &bindingstypes.DenomsByCreatorResponse{Denoms: denoms}, nil +} + +// GetMetadata is q query to get the stored metadata of a denom +func (qp QueryPlugin) GetMetadata(ctx sdk.Context, denom string) (*bindingstypes.MetadataResponse, error) { + metadata, found := qp.bankKeeper.GetDenomMetaData(ctx, denom) + var parsed *bindingstypes.Metadata + if found { + parsed = SdkMetadataToWasm(metadata) + } + return &bindingstypes.MetadataResponse{Metadata: parsed}, nil +} + +func (qp QueryPlugin) GetParams(ctx sdk.Context) (*bindingstypes.ParamsResponse, error) { + params := qp.tokenFactoryKeeper.GetParams(ctx) + return &bindingstypes.ParamsResponse{ + Params: bindingstypes.Params{ + DenomCreationFee: ConvertSdkCoinsToWasmCoins(params.DenomCreationFee), + }, + }, nil +} diff --git a/x/tokenfactory/bindings/query_plugin.go b/x/tokenfactory/bindings/query_plugin.go new file mode 100644 index 000000000..924d81bd0 --- /dev/null +++ b/x/tokenfactory/bindings/query_plugin.go @@ -0,0 +1,122 @@ +package bindings + +import ( + "encoding/json" + "fmt" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + bindingstypes "github.com/quasarlabs/quasarnode/x/tokenfactory/bindings/types" +) + +// CustomQuerier dispatches custom CosmWasm bindings queries. +func CustomQuerier(qp *QueryPlugin) func(ctx sdk.Context, request json.RawMessage) ([]byte, error) { + return func(ctx sdk.Context, request json.RawMessage) ([]byte, error) { + var contractQuery bindingstypes.TokenFactoryQuery + if err := json.Unmarshal(request, &contractQuery); err != nil { + return nil, sdkerrors.Wrap(err, "quasar query") + } + if contractQuery.Token == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "nil token field") + } + tokenQuery := contractQuery.Token + + switch { + case tokenQuery.FullDenom != nil: + creator := tokenQuery.FullDenom.CreatorAddr + subdenom := tokenQuery.FullDenom.Subdenom + + fullDenom, err := GetFullDenom(creator, subdenom) + if err != nil { + return nil, sdkerrors.Wrap(err, "osmo full denom query") + } + + res := bindingstypes.FullDenomResponse{ + Denom: fullDenom, + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, sdkerrors.Wrap(err, "failed to marshal FullDenomResponse") + } + + return bz, nil + + case tokenQuery.Admin != nil: + res, err := qp.GetDenomAdmin(ctx, tokenQuery.Admin.Denom) + if err != nil { + return nil, err + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, fmt.Errorf("failed to JSON marshal AdminResponse: %w", err) + } + + return bz, nil + + case tokenQuery.Metadata != nil: + res, err := qp.GetMetadata(ctx, tokenQuery.Metadata.Denom) + if err != nil { + return nil, err + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, fmt.Errorf("failed to JSON marshal MetadataResponse: %w", err) + } + + return bz, nil + + case tokenQuery.DenomsByCreator != nil: + res, err := qp.GetDenomsByCreator(ctx, tokenQuery.DenomsByCreator.Creator) + if err != nil { + return nil, err + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, fmt.Errorf("failed to JSON marshal DenomsByCreatorResponse: %w", err) + } + + return bz, nil + + case tokenQuery.Params != nil: + res, err := qp.GetParams(ctx) + if err != nil { + return nil, err + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, fmt.Errorf("failed to JSON marshal ParamsResponse: %w", err) + } + + return bz, nil + + default: + return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown token query variant"} + } + } +} + +// ConvertSdkCoinsToWasmCoins converts sdk type coins to wasm vm type coins +func ConvertSdkCoinsToWasmCoins(coins []sdk.Coin) wasmvmtypes.Coins { + var toSend wasmvmtypes.Coins + for _, coin := range coins { + c := ConvertSdkCoinToWasmCoin(coin) + toSend = append(toSend, c) + } + return toSend +} + +// ConvertSdkCoinToWasmCoin converts a sdk type coin to a wasm vm type coin +func ConvertSdkCoinToWasmCoin(coin sdk.Coin) wasmvmtypes.Coin { + return wasmvmtypes.Coin{ + Denom: coin.Denom, + // Note: tokenfactory tokens have 18 decimal places, so 10^22 is common, no longer in u64 range + Amount: coin.Amount.String(), + } +} diff --git a/x/tokenfactory/bindings/testdata/download_releases.sh b/x/tokenfactory/bindings/testdata/download_releases.sh new file mode 100755 index 000000000..5413f3bf7 --- /dev/null +++ b/x/tokenfactory/bindings/testdata/download_releases.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -o errexit -o nounset -o pipefail +command -v shellcheck > /dev/null && shellcheck "$0" + +if [ $# -ne 1 ]; then + echo "Usage: ./download_releases.sh RELEASE_TAG" + exit 1 +fi + +tag="$1" + +# From CosmosContracts/token-bindings + +url="https://github.com/CosmWasm/token-bindings/releases/download/$tag/token_reflect.wasm" +echo "Downloading $url ..." +wget -O "token_reflect.wasm" "$url" + +rm -f version.txt +echo "$tag" >version.txt \ No newline at end of file diff --git a/x/tokenfactory/bindings/testdata/token_reflect.wasm b/x/tokenfactory/bindings/testdata/token_reflect.wasm new file mode 100755 index 0000000000000000000000000000000000000000..c27ec80a02330fe5bd590f0a981b8a3fb7150f40 GIT binary patch literal 2194768 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

9<_n5dWyQCq;g3Jjv|KCjTw_?A+Ol+=VEn@ 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�<1Z@f>~~`F5q( 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%0D~nkZL3=ix(<)A;-}&~;-!H=yVD76v(FE}-OmPB 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�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

3#o6ASV7kHAPhh@O9o>k-lAok5*T2B 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∨Cf#aya`e{w?I6+*5&1 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 0 { + require.Error(t, err) + actualErrMsg := err.Error() + require.Equal(t, spec.expErrMsg, actualErrMsg) + return + } + require.NoError(t, err) + }) + } +} + +func TestMint(t *testing.T) { + creator := RandomAccountAddress() + tokenz, ctx := SetupCustomApp(t, creator) + + // Fund actor with 100 base denom creation fees + tokenCreationFeeAmt := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, tokenz, creator, tokenCreationFeeAmt) + + // Create denoms for valid mint tests + validDenom := bindings.CreateDenom{ + Subdenom: "MOON", + } + _, err := wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, &validDenom) + require.NoError(t, err) + + emptyDenom := bindings.CreateDenom{ + Subdenom: "", + } + _, err = wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, &emptyDenom) + require.NoError(t, err) + + validDenomStr := fmt.Sprintf("factory/%s/%s", creator.String(), validDenom.Subdenom) + emptyDenomStr := fmt.Sprintf("factory/%s/%s", creator.String(), emptyDenom.Subdenom) + + lucky := RandomAccountAddress() + + // lucky was broke + balances := tokenz.BankKeeper.GetAllBalances(ctx, lucky) + require.Empty(t, balances) + + amount, ok := sdk.NewIntFromString("8080") + require.True(t, ok) + + specs := map[string]struct { + mint *bindings.MintTokens + expErr bool + }{ + "valid mint": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: amount, + MintToAddress: lucky.String(), + }, + }, + "empty sub-denom": { + mint: &bindings.MintTokens{ + Denom: emptyDenomStr, + Amount: amount, + MintToAddress: lucky.String(), + }, + expErr: false, + }, + "nonexistent sub-denom": { + mint: &bindings.MintTokens{ + Denom: fmt.Sprintf("factory/%s/%s", creator.String(), "SUN"), + Amount: amount, + MintToAddress: lucky.String(), + }, + expErr: true, + }, + "invalid sub-denom": { + mint: &bindings.MintTokens{ + Denom: "sub-denom_2", + Amount: amount, + MintToAddress: lucky.String(), + }, + expErr: true, + }, + "zero amount": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: sdk.ZeroInt(), + MintToAddress: lucky.String(), + }, + expErr: true, + }, + "negative amount": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: amount.Neg(), + MintToAddress: lucky.String(), + }, + expErr: true, + }, + "empty recipient": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: amount, + MintToAddress: "", + }, + expErr: true, + }, + "invalid recipient": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: amount, + MintToAddress: "invalid", + }, + expErr: true, + }, + "null mint": { + mint: nil, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // when + gotErr := wasmbinding.PerformMint(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, spec.mint) + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} + +func TestBurn(t *testing.T) { + creator := RandomAccountAddress() + tokenz, ctx := SetupCustomApp(t, creator) + + // Fund actor with 100 base denom creation fees + tokenCreationFeeAmt := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, tokenz, creator, tokenCreationFeeAmt) + + // Create denoms for valid burn tests + validDenom := bindings.CreateDenom{ + Subdenom: "MOON", + } + _, err := wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, &validDenom) + require.NoError(t, err) + + emptyDenom := bindings.CreateDenom{ + Subdenom: "", + } + _, err = wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, &emptyDenom) + require.NoError(t, err) + + lucky := RandomAccountAddress() + + // lucky was broke + balances := tokenz.BankKeeper.GetAllBalances(ctx, lucky) + require.Empty(t, balances) + + validDenomStr := fmt.Sprintf("factory/%s/%s", creator.String(), validDenom.Subdenom) + emptyDenomStr := fmt.Sprintf("factory/%s/%s", creator.String(), emptyDenom.Subdenom) + mintAmount, ok := sdk.NewIntFromString("8080") + require.True(t, ok) + + specs := map[string]struct { + burn *bindings.BurnTokens + expErr bool + }{ + "valid burn": { + burn: &bindings.BurnTokens{ + Denom: validDenomStr, + Amount: mintAmount, + BurnFromAddress: creator.String(), + }, + expErr: false, + }, + "non admin address": { + burn: &bindings.BurnTokens{ + Denom: validDenomStr, + Amount: mintAmount, + BurnFromAddress: lucky.String(), + }, + expErr: true, + }, + "empty sub-denom": { + burn: &bindings.BurnTokens{ + Denom: emptyDenomStr, + Amount: mintAmount, + BurnFromAddress: creator.String(), + }, + expErr: false, + }, + "invalid sub-denom": { + burn: &bindings.BurnTokens{ + Denom: "sub-denom_2", + Amount: mintAmount, + BurnFromAddress: creator.String(), + }, + expErr: true, + }, + "non-minted denom": { + burn: &bindings.BurnTokens{ + Denom: fmt.Sprintf("factory/%s/%s", creator.String(), "SUN"), + Amount: mintAmount, + BurnFromAddress: creator.String(), + }, + expErr: true, + }, + "zero amount": { + burn: &bindings.BurnTokens{ + Denom: validDenomStr, + Amount: sdk.ZeroInt(), + BurnFromAddress: creator.String(), + }, + expErr: true, + }, + "negative amount": { + burn: nil, + expErr: true, + }, + "null burn": { + burn: &bindings.BurnTokens{ + Denom: validDenomStr, + Amount: mintAmount.Neg(), + BurnFromAddress: creator.String(), + }, + expErr: true, + }, + } + + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // Mint valid denom str and empty denom string for burn test + mintBinding := &bindings.MintTokens{ + Denom: validDenomStr, + Amount: mintAmount, + MintToAddress: creator.String(), + } + err := wasmbinding.PerformMint(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, mintBinding) + require.NoError(t, err) + + emptyDenomMintBinding := &bindings.MintTokens{ + Denom: emptyDenomStr, + Amount: mintAmount, + MintToAddress: creator.String(), + } + err = wasmbinding.PerformMint(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, emptyDenomMintBinding) + require.NoError(t, err) + + // when + gotErr := wasmbinding.PerformBurn(&tokenz.TokenFactoryKeeper, ctx, creator, spec.burn) + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} +*/ diff --git a/x/tokenfactory/bindings/validate_queries_test.go b/x/tokenfactory/bindings/validate_queries_test.go new file mode 100644 index 000000000..b5c276170 --- /dev/null +++ b/x/tokenfactory/bindings/validate_queries_test.go @@ -0,0 +1,117 @@ +package bindings_test + +/* +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + + wasmbinding "github.com/quasarlabs/quasarnode/x/tokenfactory/bindings" +) + +func TestFullDenom(t *testing.T) { + actor := RandomAccountAddress() + + specs := map[string]struct { + addr string + subdenom string + expFullDenom string + expErr bool + }{ + "valid address": { + addr: actor.String(), + subdenom: "subDenom1", + expFullDenom: fmt.Sprintf("factory/%s/subDenom1", actor.String()), + }, + "empty address": { + addr: "", + subdenom: "subDenom1", + expErr: true, + }, + "invalid address": { + addr: "invalid", + subdenom: "subDenom1", + expErr: true, + }, + "empty sub-denom": { + addr: actor.String(), + subdenom: "", + expFullDenom: fmt.Sprintf("factory/%s/", actor.String()), + }, + "invalid sub-denom (contains underscore)": { + addr: actor.String(), + subdenom: "sub_denom", + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // when + gotFullDenom, gotErr := wasmbinding.GetFullDenom(spec.addr, spec.subdenom) + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expFullDenom, gotFullDenom, "exp %s but got %s", spec.expFullDenom, gotFullDenom) + }) + } +} + +func TestDenomAdmin(t *testing.T) { + addr := RandomAccountAddress() + app, ctx := SetupCustomApp(t, addr) + + // set token creation fee to zero to make testing easier + tfParams := app.TokenFactoryKeeper.GetParams(ctx) + tfParams.DenomCreationFee = sdk.NewCoins() + app.TokenFactoryKeeper.SetParams(ctx, tfParams) + + // create a subdenom via the token factory + admin := sdk.AccAddress([]byte("addr1_______________")) + tfDenom, err := app.TokenFactoryKeeper.CreateDenom(ctx, admin.String(), "subdenom") + require.NoError(t, err) + require.NotEmpty(t, tfDenom) + + queryPlugin := wasmbinding.NewQueryPlugin(&app.BankKeeper, &app.TokenFactoryKeeper) + + testCases := []struct { + name string + denom string + expectErr bool + expectAdmin string + }{ + { + name: "valid token factory denom", + denom: tfDenom, + expectAdmin: admin.String(), + }, + { + name: "invalid token factory denom", + denom: "uosmo", + expectErr: false, + expectAdmin: "", + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + resp, err := queryPlugin.GetDenomAdmin(ctx, tc.denom) + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.NotNil(t, resp) + require.Equal(t, tc.expectAdmin, resp.Admin) + } + }) + } +} +*/ diff --git a/x/tokenfactory/bindings/wasm.go b/x/tokenfactory/bindings/wasm.go new file mode 100644 index 000000000..2bdef9788 --- /dev/null +++ b/x/tokenfactory/bindings/wasm.go @@ -0,0 +1,29 @@ +package bindings + +import ( + "github.com/CosmWasm/wasmd/x/wasm" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + + tokenfactorykeeper "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" +) + +func RegisterCustomPlugins( + bank *bankkeeper.BaseKeeper, + tokenFactory *tokenfactorykeeper.Keeper, +) []wasmkeeper.Option { + wasmQueryPlugin := NewQueryPlugin(bank, tokenFactory) + + queryPluginOpt := wasmkeeper.WithQueryPlugins(&wasmkeeper.QueryPlugins{ + Custom: CustomQuerier(wasmQueryPlugin), + }) + messengerDecoratorOpt := wasmkeeper.WithMessageHandlerDecorator( + CustomMessageDecorator(bank, tokenFactory), + ) + + return []wasm.Option{ + queryPluginOpt, + messengerDecoratorOpt, + } +} diff --git a/x/tokenfactory/client/cli/query.go b/x/tokenfactory/client/cli/query.go new file mode 100644 index 000000000..4ce929319 --- /dev/null +++ b/x/tokenfactory/client/cli/query.go @@ -0,0 +1,122 @@ +package cli + +import ( + "fmt" + + // "strings" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + + // "github.com/cosmos/cosmos-sdk/client/flags" + // sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd() *cobra.Command { + // Group tokenfactory queries under a subcommand + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + GetParams(), + GetCmdDenomAuthorityMetadata(), + GetCmdDenomsFromCreator(), + ) + + return cmd +} + +// GetParams returns the params for the module +func GetParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params [flags]", + Short: "Get the params for the x/tokenfactory module", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdDenomAuthorityMetadata returns the authority metadata for a queried denom +func GetCmdDenomAuthorityMetadata() *cobra.Command { + cmd := &cobra.Command{ + Use: "denom-authority-metadata [denom] [flags]", + Short: "Get the authority metadata for a specific denom", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.DenomAuthorityMetadata(cmd.Context(), &types.QueryDenomAuthorityMetadataRequest{ + Denom: args[0], + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdDenomsFromCreator a command to get a list of all tokens created by a specific creator address +func GetCmdDenomsFromCreator() *cobra.Command { + cmd := &cobra.Command{ + Use: "denoms-from-creator [creator address] [flags]", + Short: "Returns a list of all tokens created by a specific creator address", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.DenomsFromCreator(cmd.Context(), &types.QueryDenomsFromCreatorRequest{ + Creator: args[0], + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/tokenfactory/client/cli/tx.go b/x/tokenfactory/client/cli/tx.go new file mode 100644 index 000000000..93ad14e8e --- /dev/null +++ b/x/tokenfactory/client/cli/tx.go @@ -0,0 +1,231 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + NewCreateDenomCmd(), + NewMintCmd(), + NewBurnCmd(), + NewMintToCmd(), + NewBurnFromCmd(), + NewChangeAdminCmd(), + ) + + return cmd +} + +// NewCreateDenomCmd broadcast MsgCreateDenom +func NewCreateDenomCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "create-denom [subdenom] [flags]", + Short: "create a new denom from an account", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + msg := types.NewMsgCreateDenom( + clientCtx.GetFromAddress().String(), + args[0], + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewMintCmd broadcast MsgMint +func NewMintCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "mint [amount] [flags]", + Short: "Mint a denom to your address. Must have admin authority to do so.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + amount, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgMint( + clientCtx.GetFromAddress().String(), + amount, + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewBurnCmd broadcast MsgBurn +func NewBurnCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "burn [amount] [flags]", + Short: "Burn tokens from your address. Must have admin authority to do so.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + amount, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgBurn( + clientCtx.GetFromAddress().String(), + amount, + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewChangeAdminCmd broadcast MsgChangeAdmin +func NewChangeAdminCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "change-admin [denom] [new-admin-address] [flags]", + Short: "Changes the admin address for a factory-created denom. Must have admin authority to do so.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + msg := types.NewMsgChangeAdmin( + clientCtx.GetFromAddress().String(), + args[0], + args[1], + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewMintToCmd broadcast MsgMintTo +func NewMintToCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "mint-to [address] [amount] [flags]", + Short: "Mint a denom to an address. Must have admin authority to do so.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + toAddr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + amount, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgMintTo( + clientCtx.GetFromAddress().String(), + amount, + toAddr.String(), + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewBurnFromCmd broadcast MsgBurnFrom +func NewBurnFromCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "burn-from [address] [amount] [flags]", + Short: "Burn tokens from an address. Must have admin authority to do so.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + fromAddr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + amount, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgBurnFrom( + clientCtx.GetFromAddress().String(), + amount, + fromAddr.String(), + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/tokenfactory/keeper/admins.go b/x/tokenfactory/keeper/admins.go new file mode 100644 index 000000000..fde574738 --- /dev/null +++ b/x/tokenfactory/keeper/admins.go @@ -0,0 +1,49 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/gogo/protobuf/proto" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +// GetAuthorityMetadata returns the authority metadata for a specific denom +func (k Keeper) GetAuthorityMetadata(ctx sdk.Context, denom string) (types.DenomAuthorityMetadata, error) { + bz := k.GetDenomPrefixStore(ctx, denom).Get([]byte(types.DenomAuthorityMetadataKey)) + + metadata := types.DenomAuthorityMetadata{} + err := proto.Unmarshal(bz, &metadata) + if err != nil { + return types.DenomAuthorityMetadata{}, err + } + return metadata, nil +} + +// setAuthorityMetadata stores authority metadata for a specific denom +func (k Keeper) setAuthorityMetadata(ctx sdk.Context, denom string, metadata types.DenomAuthorityMetadata) error { + err := metadata.Validate() + if err != nil { + return err + } + + store := k.GetDenomPrefixStore(ctx, denom) + + bz, err := proto.Marshal(&metadata) + if err != nil { + return err + } + + store.Set([]byte(types.DenomAuthorityMetadataKey), bz) + return nil +} + +func (k Keeper) setAdmin(ctx sdk.Context, denom string, admin string) error { + metadata, err := k.GetAuthorityMetadata(ctx, denom) + if err != nil { + return err + } + + metadata.Admin = admin + + return k.setAuthorityMetadata(ctx, denom, metadata) +} diff --git a/x/tokenfactory/keeper/bankactions.go b/x/tokenfactory/keeper/bankactions.go new file mode 100644 index 000000000..874abf160 --- /dev/null +++ b/x/tokenfactory/keeper/bankactions.go @@ -0,0 +1,52 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +func (k Keeper) mintTo(ctx sdk.Context, amount sdk.Coin, mintTo string) error { + // verify that denom is an x/tokenfactory denom + _, _, err := types.DeconstructDenom(amount.Denom) + if err != nil { + return err + } + + err = k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(amount)) + if err != nil { + return err + } + + addr, err := sdk.AccAddressFromBech32(mintTo) + if err != nil { + return err + } + + return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, + addr, + sdk.NewCoins(amount)) +} + +func (k Keeper) burnFrom(ctx sdk.Context, amount sdk.Coin, burnFrom string) error { + // verify that denom is an x/tokenfactory denom + _, _, err := types.DeconstructDenom(amount.Denom) + if err != nil { + return err + } + + addr, err := sdk.AccAddressFromBech32(burnFrom) + if err != nil { + return err + } + + err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, + addr, + types.ModuleName, + sdk.NewCoins(amount)) + if err != nil { + return err + } + + return k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(amount)) +} diff --git a/x/tokenfactory/keeper/createdenom.go b/x/tokenfactory/keeper/createdenom.go new file mode 100644 index 000000000..928909175 --- /dev/null +++ b/x/tokenfactory/keeper/createdenom.go @@ -0,0 +1,93 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +// ConvertToBaseToken converts a fee amount in a whitelisted fee token to the base fee token amount +func (k Keeper) CreateDenom(ctx sdk.Context, creatorAddr string, subdenom string) (newTokenDenom string, err error) { + denom, err := k.validateCreateDenom(ctx, creatorAddr, subdenom) + if err != nil { + return "", err + } + + err = k.chargeForCreateDenom(ctx, creatorAddr, subdenom) + if err != nil { + return "", err + } + + err = k.createDenomAfterValidation(ctx, creatorAddr, denom) + return denom, err +} + +// Runs CreateDenom logic after the charge and all denom validation has been handled. +// Made into a second function for genesis initialization. +func (k Keeper) createDenomAfterValidation(ctx sdk.Context, creatorAddr string, denom string) (err error) { + _, exists := k.bankKeeper.GetDenomMetaData(ctx, denom) + if !exists { + denomMetaData := banktypes.Metadata{ + DenomUnits: []*banktypes.DenomUnit{{ + Denom: denom, + Exponent: 0, + }}, + Base: denom, + } + + k.bankKeeper.SetDenomMetaData(ctx, denomMetaData) + } + + authorityMetadata := types.DenomAuthorityMetadata{ + Admin: creatorAddr, + } + err = k.setAuthorityMetadata(ctx, denom, authorityMetadata) + if err != nil { + return err + } + + k.addDenomFromCreator(ctx, creatorAddr, denom) + return nil +} + +func (k Keeper) validateCreateDenom(ctx sdk.Context, creatorAddr string, subdenom string) (newTokenDenom string, err error) { + // Temporary check until IBC bug is sorted out + if k.bankKeeper.HasSupply(ctx, subdenom) { + return "", fmt.Errorf("temporary error until IBC bug is sorted out, " + + "can't create subdenoms that are the same as a native denom") + } + + denom, err := types.GetTokenDenom(creatorAddr, subdenom) + if err != nil { + return "", err + } + + _, found := k.bankKeeper.GetDenomMetaData(ctx, denom) + if found { + return "", types.ErrDenomExists + } + + return denom, nil +} + +func (k Keeper) chargeForCreateDenom(ctx sdk.Context, creatorAddr string, subdenom string) (err error) { + // Send creation fee to community pool + creationFee := k.GetParams(ctx).DenomCreationFee + accAddr, err := sdk.AccAddressFromBech32(creatorAddr) + if err != nil { + return err + } + if creationFee != nil && !creationFee.IsZero() { + if err := k.communityPoolKeeper.FundCommunityPool(ctx, creationFee, accAddr); err != nil { + return err + } + } else { + gasIncrease := k.GetParams(ctx).DenomCreationGasConsume + ctx.GasMeter().ConsumeGas(gasIncrease, "consume denom creation gas") + } + + return nil +} diff --git a/x/tokenfactory/keeper/createdenom_test.go b/x/tokenfactory/keeper/createdenom_test.go new file mode 100644 index 000000000..32d8b2c02 --- /dev/null +++ b/x/tokenfactory/keeper/createdenom_test.go @@ -0,0 +1,48 @@ +package keeper_test + +import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "testing" + + "github.com/quasarlabs/quasarnode/testutil" + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" + "github.com/stretchr/testify/require" +) + +func TestMsgCreateDenom(t *testing.T) { + setup := testutil.NewTestSetup(t) + fundAccsAmount := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, + types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100)), sdk.NewCoin("uosmo", sdk.NewInt(10000000))) + for _, acc := range setup.TestAccs { + setup.FundAcc(t, acc, fundAccsAmount) + } + ctx, tokenFactoryKeeper := setup.Ctx, setup.Keepers.TfKeeper + bankKeeper := setup.Keepers.BankKeeper + params := types.DefaultParams() + + tokenFactoryKeeper.SetParams(ctx, params) + denomCreationFee := tokenFactoryKeeper.GetParams(ctx).DenomCreationFee + + // Get balance of acc 0 before creating a denom + // preCreateBalance := bankKeeper.GetBalance(ctx, suite.TestAccs[0], denomCreationFee[0].Denom) + preCreateBalance := bankKeeper.GetBalance(ctx, setup.TestAccs[0], denomCreationFee[0].Denom) + fmt.Printf("balance=%v", preCreateBalance) + res, err := tokenFactoryKeeper.CreateDenom(ctx, setup.TestAccs[0].String(), "bitcoin") + require.NoError(t, err) + require.NotEmpty(t, res) + + // Make sure that the admin is set correctly + denom_metadata, err := tokenFactoryKeeper.GetAuthorityMetadata(ctx, res) + require.NoError(t, err) + require.NotEmpty(t, denom_metadata) + require.Equal(t, setup.TestAccs[0].String(), denom_metadata.Admin) + + postCreateBalance := bankKeeper.GetBalance(ctx, setup.TestAccs[0], tokenFactoryKeeper.GetParams(ctx).DenomCreationFee[0].Denom) + require.True(t, preCreateBalance.Sub(postCreateBalance).IsEqual(denomCreationFee[0])) + + // Make sure that a second version of the same denom can't be recreated + res1, err1 := tokenFactoryKeeper.CreateDenom(ctx, setup.TestAccs[0].String(), "bitcoin") + require.Error(t, err1) + require.Empty(t, res1) +} diff --git a/x/tokenfactory/keeper/creators.go b/x/tokenfactory/keeper/creators.go new file mode 100644 index 000000000..570d54b9f --- /dev/null +++ b/x/tokenfactory/keeper/creators.go @@ -0,0 +1,27 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (k Keeper) addDenomFromCreator(ctx sdk.Context, creator, denom string) { + store := k.GetCreatorPrefixStore(ctx, creator) + store.Set([]byte(denom), []byte(denom)) +} + +func (k Keeper) GetDenomsFromCreator(ctx sdk.Context, creator string) []string { + store := k.GetCreatorPrefixStore(ctx, creator) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + denoms := []string{} + for ; iterator.Valid(); iterator.Next() { + denoms = append(denoms, string(iterator.Key())) + } + return denoms +} + +func (k Keeper) GetAllDenomsIterator(ctx sdk.Context) sdk.Iterator { + return k.GetCreatorsPrefixStore(ctx).Iterator(nil, nil) +} diff --git a/x/tokenfactory/keeper/genesis.go b/x/tokenfactory/keeper/genesis.go new file mode 100644 index 000000000..016be30c0 --- /dev/null +++ b/x/tokenfactory/keeper/genesis.go @@ -0,0 +1,58 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +// InitGenesis initializes the tokenfactory module's state from a provided genesis +// state. +func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { + k.CreateModuleAccount(ctx) + + if genState.Params.DenomCreationFee == nil { + genState.Params.DenomCreationFee = sdk.NewCoins() + } + k.SetParams(ctx, genState.Params) + + for _, genDenom := range genState.GetFactoryDenoms() { + creator, _, err := types.DeconstructDenom(genDenom.GetDenom()) + if err != nil { + panic(err) + } + err = k.createDenomAfterValidation(ctx, creator, genDenom.GetDenom()) + if err != nil { + panic(err) + } + err = k.setAuthorityMetadata(ctx, genDenom.GetDenom(), genDenom.GetAuthorityMetadata()) + if err != nil { + panic(err) + } + } +} + +// ExportGenesis returns the tokenfactory module's exported genesis. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + genDenoms := []types.GenesisDenom{} + iterator := k.GetAllDenomsIterator(ctx) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + denom := string(iterator.Value()) + + authorityMetadata, err := k.GetAuthorityMetadata(ctx, denom) + if err != nil { + panic(err) + } + + genDenoms = append(genDenoms, types.GenesisDenom{ + Denom: denom, + AuthorityMetadata: authorityMetadata, + }) + } + + return &types.GenesisState{ + FactoryDenoms: genDenoms, + Params: k.GetParams(ctx), + } +} diff --git a/x/tokenfactory/keeper/genesis_test.go b/x/tokenfactory/keeper/genesis_test.go new file mode 100644 index 000000000..c165d16f0 --- /dev/null +++ b/x/tokenfactory/keeper/genesis_test.go @@ -0,0 +1,62 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/quasarlabs/quasarnode/testutil" + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" + "github.com/stretchr/testify/require" + "testing" +) + +func TestGenesis(t *testing.T) { + setup := testutil.NewTestSetup(t) + ctx, tokenFactoryKeeper := setup.Ctx, setup.Keepers.TfKeeper + bankKeeper := setup.Keepers.BankKeeper + accountKeeper := setup.Keepers.AccountKeeper + genesisState := types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + }, + }, + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/diff-admin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + }, + }, + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/litecoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + }, + }, + }, + } + + // Test both with bank denom metadata set, and not set. + for i, denom := range genesisState.FactoryDenoms { + // hacky, sets bank metadata to exist if i != 0, to cover both cases. + if i != 0 { + bankKeeper.SetDenomMetaData(ctx, banktypes.Metadata{Base: denom.GetDenom()}) + } + } + + // check before initGenesis that the module account is nil + tokenfactoryModuleAccount := accountKeeper.GetAccount(ctx, accountKeeper.GetModuleAddress(types.ModuleName)) + require.Nil(t, tokenfactoryModuleAccount) + + tokenFactoryKeeper.SetParams(ctx, types.Params{DenomCreationFee: sdk.Coins{sdk.NewInt64Coin("uosmo", 100)}}) + tokenFactoryKeeper.InitGenesis(ctx, genesisState) + + // check that the module account is now initialized + tokenfactoryModuleAccount = accountKeeper.GetAccount(ctx, accountKeeper.GetModuleAddress(types.ModuleName)) + require.NotNil(t, tokenfactoryModuleAccount) + + exportedGenesis := tokenFactoryKeeper.ExportGenesis(ctx) + require.NotNil(t, exportedGenesis) + require.Equal(t, genesisState, *exportedGenesis) +} diff --git a/x/tokenfactory/keeper/grpc_query.go b/x/tokenfactory/keeper/grpc_query.go new file mode 100644 index 000000000..666f92666 --- /dev/null +++ b/x/tokenfactory/keeper/grpc_query.go @@ -0,0 +1,35 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +var _ types.QueryServer = Keeper{} + +func (k Keeper) Params(ctx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + params := k.GetParams(sdkCtx) + + return &types.QueryParamsResponse{Params: params}, nil +} + +func (k Keeper) DenomAuthorityMetadata(ctx context.Context, req *types.QueryDenomAuthorityMetadataRequest) (*types.QueryDenomAuthorityMetadataResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + authorityMetadata, err := k.GetAuthorityMetadata(sdkCtx, req.GetDenom()) + if err != nil { + return nil, err + } + + return &types.QueryDenomAuthorityMetadataResponse{AuthorityMetadata: authorityMetadata}, nil +} + +func (k Keeper) DenomsFromCreator(ctx context.Context, req *types.QueryDenomsFromCreatorRequest) (*types.QueryDenomsFromCreatorResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + denoms := k.GetDenomsFromCreator(sdkCtx, req.GetCreator()) + return &types.QueryDenomsFromCreatorResponse{Denoms: denoms}, nil +} diff --git a/x/tokenfactory/keeper/keeper.go b/x/tokenfactory/keeper/keeper.go new file mode 100644 index 000000000..a9e7f2380 --- /dev/null +++ b/x/tokenfactory/keeper/keeper.go @@ -0,0 +1,81 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +type ( + Keeper struct { + storeKey sdk.StoreKey + + paramSpace paramtypes.Subspace + + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + communityPoolKeeper types.CommunityPoolKeeper + } +) + +// NewKeeper returns a new instance of the x/tokenfactory keeper +func NewKeeper( + storeKey sdk.StoreKey, + paramSpace paramtypes.Subspace, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, + communityPoolKeeper types.CommunityPoolKeeper, +) Keeper { + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + + return Keeper{ + storeKey: storeKey, + paramSpace: paramSpace, + + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + communityPoolKeeper: communityPoolKeeper, + } +} + +// Logger returns a logger for the x/tokenfactory module +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +// GetDenomPrefixStore returns the substore for a specific denom +func (k Keeper) GetDenomPrefixStore(ctx sdk.Context, denom string) sdk.KVStore { + store := ctx.KVStore(k.storeKey) + return prefix.NewStore(store, types.GetDenomPrefixStore(denom)) +} + +// GetCreatorPrefixStore returns the substore for a specific creator address +func (k Keeper) GetCreatorPrefixStore(ctx sdk.Context, creator string) sdk.KVStore { + store := ctx.KVStore(k.storeKey) + return prefix.NewStore(store, types.GetCreatorPrefix(creator)) +} + +// GetCreatorsPrefixStore returns the substore that contains a list of creators +func (k Keeper) GetCreatorsPrefixStore(ctx sdk.Context) sdk.KVStore { + store := ctx.KVStore(k.storeKey) + return prefix.NewStore(store, types.GetCreatorsPrefix()) +} + +// CreateModuleAccount creates a module account with minting and burning capabilities +// This account isn't intended to store any coins, +// it purely mints and burns them on behalf of the admin of respective denoms, +// and sends to the relevant address. +func (k Keeper) CreateModuleAccount(ctx sdk.Context) { + moduleAcc := authtypes.NewEmptyModuleAccount(types.ModuleName, authtypes.Minter, authtypes.Burner) + k.accountKeeper.SetModuleAccount(ctx, moduleAcc) +} diff --git a/x/tokenfactory/keeper/msg_server.go b/x/tokenfactory/keeper/msg_server.go new file mode 100644 index 000000000..9f5f1b7a9 --- /dev/null +++ b/x/tokenfactory/keeper/msg_server.go @@ -0,0 +1,178 @@ +package keeper + +import ( + "context" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +func (server msgServer) CreateDenom(goCtx context.Context, msg *types.MsgCreateDenom) (*types.MsgCreateDenomResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + denom, err := server.Keeper.CreateDenom(ctx, msg.Sender, msg.Subdenom) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgCreateDenom, + sdk.NewAttribute(types.AttributeCreator, msg.Sender), + sdk.NewAttribute(types.AttributeNewTokenDenom, denom), + ), + }) + + return &types.MsgCreateDenomResponse{ + NewTokenDenom: denom, + }, nil +} + +func (server msgServer) Mint(goCtx context.Context, msg *types.MsgMint) (*types.MsgMintResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // pay some extra gas cost to give a better error here. + _, denomExists := server.bankKeeper.GetDenomMetaData(ctx, msg.Amount.Denom) + if !denomExists { + return nil, types.ErrDenomDoesNotExist.Wrapf("denom: %s", msg.Amount.Denom) + } + + authorityMetadata, err := server.Keeper.GetAuthorityMetadata(ctx, msg.Amount.GetDenom()) + if err != nil { + return nil, err + } + + if msg.Sender != authorityMetadata.GetAdmin() { + return nil, types.ErrUnauthorized + } + + if msg.MintToAddress == "" { + msg.MintToAddress = msg.Sender + } + + err = server.Keeper.mintTo(ctx, msg.Amount, msg.MintToAddress) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgMint, + sdk.NewAttribute(types.AttributeMsgSender, msg.Sender), + sdk.NewAttribute(types.AttributeMintToAddress, msg.MintToAddress), + sdk.NewAttribute(types.AttributeAmount, msg.Amount.String()), + ), + }) + + return &types.MsgMintResponse{}, nil +} + +func (server msgServer) Burn(goCtx context.Context, msg *types.MsgBurn) (*types.MsgBurnResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + authorityMetadata, err := server.Keeper.GetAuthorityMetadata(ctx, msg.Amount.GetDenom()) + if err != nil { + return nil, err + } + + if msg.Sender != authorityMetadata.GetAdmin() { + return nil, types.ErrUnauthorized + } + if msg.BurnFromAddress == "" { + msg.BurnFromAddress = msg.Sender + } + + accountI := server.Keeper.accountKeeper.GetAccount(ctx, sdk.AccAddress(msg.BurnFromAddress)) + _, ok := accountI.(authtypes.ModuleAccountI) + if ok { + return nil, types.ErrBurnFromModuleAccount + } + + err = server.Keeper.burnFrom(ctx, msg.Amount, msg.BurnFromAddress) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgBurn, + sdk.NewAttribute(types.AttributeMsgSender, msg.Sender), + sdk.NewAttribute(types.AttributeBurnFromAddress, msg.BurnFromAddress), + sdk.NewAttribute(types.AttributeAmount, msg.Amount.String()), + ), + }) + + return &types.MsgBurnResponse{}, nil +} + +func (server msgServer) ChangeAdmin(goCtx context.Context, msg *types.MsgChangeAdmin) (*types.MsgChangeAdminResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + authorityMetadata, err := server.Keeper.GetAuthorityMetadata(ctx, msg.Denom) + if err != nil { + return nil, err + } + + if msg.Sender != authorityMetadata.GetAdmin() { + return nil, types.ErrUnauthorized + } + + err = server.Keeper.setAdmin(ctx, msg.Denom, msg.NewAdmin) + if err != nil { + return nil, err + } + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgChangeAdmin, + sdk.NewAttribute(types.AttributeDenom, msg.GetDenom()), + sdk.NewAttribute(types.AttributeNewAdmin, msg.NewAdmin), + ), + }) + + return &types.MsgChangeAdminResponse{}, nil +} + +func (server msgServer) SetDenomMetadata(goCtx context.Context, msg *types.MsgSetDenomMetadata) (*types.MsgSetDenomMetadataResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // Defense in depth validation of metadata + err := msg.Metadata.Validate() + if err != nil { + return nil, err + } + + authorityMetadata, err := server.Keeper.GetAuthorityMetadata(ctx, msg.Metadata.Base) + if err != nil { + return nil, err + } + + if msg.Sender != authorityMetadata.GetAdmin() { + return nil, types.ErrUnauthorized + } + + server.Keeper.bankKeeper.SetDenomMetaData(ctx, msg.Metadata) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgSetDenomMetadata, + sdk.NewAttribute(types.AttributeDenom, msg.Metadata.Base), + sdk.NewAttribute(types.AttributeDenomMetadata, msg.Metadata.String()), + ), + }) + + return &types.MsgSetDenomMetadataResponse{}, nil +} diff --git a/x/tokenfactory/keeper/params.go b/x/tokenfactory/keeper/params.go new file mode 100644 index 000000000..519282c5b --- /dev/null +++ b/x/tokenfactory/keeper/params.go @@ -0,0 +1,18 @@ +package keeper + +import ( + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GetParams returns the total set params. +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramSpace.GetParamSet(ctx, ¶ms) + return params +} + +// SetParams sets the total set of params. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} diff --git a/x/tokenfactory/keeper/params_test.go b/x/tokenfactory/keeper/params_test.go new file mode 100644 index 000000000..b87726a1b --- /dev/null +++ b/x/tokenfactory/keeper/params_test.go @@ -0,0 +1,19 @@ +package keeper_test + +import ( + "testing" + + "github.com/quasarlabs/quasarnode/testutil" + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" + "github.com/stretchr/testify/require" +) + +func TestGetParams(t *testing.T) { + setup := testutil.NewTestSetup(t) + ctx, k := setup.Ctx, setup.Keepers.TfKeeper + params := types.DefaultParams() + + k.SetParams(ctx, params) + + require.EqualValues(t, params, k.GetParams(ctx)) +} diff --git a/x/tokenfactory/module.go b/x/tokenfactory/module.go new file mode 100644 index 000000000..91c157bc8 --- /dev/null +++ b/x/tokenfactory/module.go @@ -0,0 +1,205 @@ +/* +The tokenfactory module allows any account to create a new token with +the name `factory/{creator address}/{subdenom}`. + +- Mint and burn user denom to and form any account +- Create a transfer of their denom between any two accounts +- Change the admin. In the future, more admin capabilities may be added. +*/ +package tokenfactory + +import ( + "context" + "encoding/json" + "fmt" + // "github.com/osmosis-labs/osmosis/v15/simulation/simtypes" + + "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" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + // "github.com/quasarlabs/quasarnode/simulation/simtypes" + // simulation "github.com/quasarlabs/quasarnode/x/tokenfactory/simulation" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/client/cli" + "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct{} + +func NewAppModuleBasic() AppModuleBasic { + return AppModuleBasic{} +} + +// Name returns the x/tokenfactory module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the x/tokenfactory module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the x/tokenfactory module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + + return genState.Validate() +} + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) //nolint:errcheck +} + +// GetTxCmd returns the x/tokenfactory module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the x/tokenfactory module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper +} + +func NewAppModule( + keeper keeper.Keeper, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(), + keeper: keeper, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + } +} + +// Name returns the x/tokenfactory module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// Route returns the x/tokenfactory module's message routing key. +func (am AppModule) Route() sdk.Route { + return sdk.Route{} +} + +// QuerierRoute returns the x/tokenfactory module's query routing key. +func (AppModule) QuerierRoute() string { return types.QuerierRoute } + +// LegacyQuerierHandler returns the x/tokenfactory module's Querier. +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// RegisterInvariants registers the x/tokenfactory module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the x/tokenfactory module's genesis initialization. It +// returns no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + cdc.MustUnmarshalJSON(gs, &genState) + + am.keeper.InitGenesis(ctx, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the x/tokenfactory module's exported genesis state as raw +// JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion implements ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock executes all ABCI BeginBlock logic respective to the tokenfactory module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock executes all ABCI EndBlock logic respective to the tokenfactory module. It +// returns no validator updates. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ___________________________________________________________________________ + +// AppModuleSimulationV2 functions +/* +// GenerateGenesisState creates a randomized GenState of the tokenfactory module. +func (am AppModule) SimulatorGenesisState(simState *module.SimulationState, s *simtypes.SimCtx) { + tfDefaultGen := types.DefaultGenesis() + tfDefaultGen.Params.DenomCreationFee = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10000000))) + tfDefaultGenJson := simState.Cdc.MustMarshalJSON(tfDefaultGen) + simState.GenState[types.ModuleName] = tfDefaultGenJson +} +*/ +/* +// WeightedOperations returns the all the lockup module operations with their respective weights. +func (am AppModule) Actions() []simtypes.Action { + return []simtypes.Action{ + simtypes.NewMsgBasedAction("create token factory token", am.keeper, simulation.RandomMsgCreateDenom), + simtypes.NewMsgBasedAction("mint token factory token", am.keeper, simulation.RandomMsgMintDenom), + simtypes.NewMsgBasedAction("burn token factory token", am.keeper, simulation.RandomMsgBurnDenom), + simtypes.NewMsgBasedAction("change admin token factory token", am.keeper, simulation.RandomMsgChangeAdmin), + } +} +*/ diff --git a/x/tokenfactory/simulation/sim_msgs.go b/x/tokenfactory/simulation/sim_msgs.go new file mode 100644 index 000000000..e52ca2b14 --- /dev/null +++ b/x/tokenfactory/simulation/sim_msgs.go @@ -0,0 +1,134 @@ +package simulation + +/* +import ( + "errors" + + legacysimulationtype "github.com/cosmos/cosmos-sdk/types/simulation" + + "github.com/osmosis-labs/osmosis/osmoutils" + "github.com/quasarlabs/quasarnode/simulation/simtypes" + "github.com/quasarlabs/quasarnode/x/tokenfactory/keeper" + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// RandomMsgCreateDenom creates a random tokenfactory denom that is no greater than 44 alphanumeric characters +func RandomMsgCreateDenom(k keeper.Keeper, sim *simtypes.SimCtx, ctx sdk.Context) (*types.MsgCreateDenom, error) { + minCoins := k.GetParams(ctx).DenomCreationFee + acc, err := sim.RandomSimAccountWithMinCoins(ctx, minCoins) + if err != nil { + return nil, err + } + + return &types.MsgCreateDenom{ + Sender: acc.Address.String(), + Subdenom: sim.RandStringOfLength(types.MaxSubdenomLength), + }, nil +} + +// RandomMsgMintDenom takes a random denom that has been created and uses the denom's admin to mint a random amount +func RandomMsgMintDenom(k keeper.Keeper, sim *simtypes.SimCtx, ctx sdk.Context) (*types.MsgMint, error) { + acc, senderExists := sim.RandomSimAccountWithConstraint(accountCreatedTokenFactoryDenom(k, ctx)) + if !senderExists { + return nil, errors.New("no addr has created a tokenfactory coin") + } + + denom, addr, err := getTokenFactoryDenomAndItsAdmin(k, sim, ctx, acc) + if err != nil { + return nil, err + } + if addr == nil { + return nil, errors.New("denom has no admin") + } + + // TODO: Replace with an improved rand exponential coin + mintAmount := sim.RandPositiveInt(sdk.NewIntFromUint64(1000_000000)) + return &types.MsgMint{ + Sender: addr.String(), + Amount: sdk.NewCoin(denom, mintAmount), + }, nil +} + +// RandomMsgBurnDenom takes a random denom that has been created and uses the denom's admin to burn a random amount +func RandomMsgBurnDenom(k keeper.Keeper, sim *simtypes.SimCtx, ctx sdk.Context) (*types.MsgBurn, error) { + acc, senderExists := sim.RandomSimAccountWithConstraint(accountCreatedTokenFactoryDenom(k, ctx)) + if !senderExists { + return nil, errors.New("no addr has created a tokenfactory coin") + } + + denom, addr, err := getTokenFactoryDenomAndItsAdmin(k, sim, ctx, acc) + if err != nil { + return nil, err + } + if addr == nil { + return nil, errors.New("denom has no admin") + } + + denomBal := sim.BankKeeper().GetBalance(ctx, addr, denom) + if denomBal.IsZero() { + return nil, errors.New("addr does not have enough balance to burn") + } + + // TODO: Replace with an improved rand exponential coin + burnAmount := sim.RandPositiveInt(denomBal.Amount) + return &types.MsgBurn{ + Sender: addr.String(), + Amount: sdk.NewCoin(denom, burnAmount), + }, nil +} + +// RandomMsgChangeAdmin takes a random denom that has been created and changes the admin to another random account +func RandomMsgChangeAdmin(k keeper.Keeper, sim *simtypes.SimCtx, ctx sdk.Context) (*types.MsgChangeAdmin, error) { + acc, senderExists := sim.RandomSimAccountWithConstraint(accountCreatedTokenFactoryDenom(k, ctx)) + if !senderExists { + return nil, errors.New("no addr has created a tokenfactory coin") + } + + denom, addr, err := getTokenFactoryDenomAndItsAdmin(k, sim, ctx, acc) + if err != nil { + return nil, err + } + if addr == nil { + return nil, errors.New("denom has no admin") + } + + newAdmin := sim.RandomSimAccount() + if newAdmin.Address.String() == addr.String() { + return nil, errors.New("new admin cannot be the same as current admin") + } + + return &types.MsgChangeAdmin{ + Sender: addr.String(), + Denom: denom, + NewAdmin: newAdmin.Address.String(), + }, nil +} + +func accountCreatedTokenFactoryDenom(k keeper.Keeper, ctx sdk.Context) simtypes.SimAccountConstraint { + return func(acc legacysimulationtype.Account) bool { + store := k.GetCreatorPrefixStore(ctx, acc.Address.String()) + iterator := store.Iterator(nil, nil) + defer iterator.Close() + return iterator.Valid() + } +} + +func getTokenFactoryDenomAndItsAdmin(k keeper.Keeper, sim *simtypes.SimCtx, ctx sdk.Context, acc legacysimulationtype.Account) (string, sdk.AccAddress, error) { + store := k.GetCreatorPrefixStore(ctx, acc.Address.String()) + denoms := osmoutils.GatherAllKeysFromStore(store) + denom := simtypes.RandSelect(sim, denoms...) + + authData, err := k.GetAuthorityMetadata(ctx, denom) + if err != nil { + return "", nil, err + } + admin := authData.Admin + addr, err := sdk.AccAddressFromBech32(admin) + if err != nil { + return "", nil, err + } + return denom, addr, nil +} +*/ diff --git a/x/tokenfactory/testhelpers/consts.go b/x/tokenfactory/testhelpers/consts.go new file mode 100644 index 000000000..d7804a372 --- /dev/null +++ b/x/tokenfactory/testhelpers/consts.go @@ -0,0 +1,8 @@ +package testhelpers + +import sdk "github.com/cosmos/cosmos-sdk/types" + +var ( + SecondaryDenom = "uion" + SecondaryAmount = sdk.NewInt(100000000) +) diff --git a/x/tokenfactory/testhelpers/suite.go b/x/tokenfactory/testhelpers/suite.go new file mode 100644 index 000000000..7df45ad15 --- /dev/null +++ b/x/tokenfactory/testhelpers/suite.go @@ -0,0 +1,66 @@ +package testhelpers + +import ( + "encoding/json" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/x/authz" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + Amino = codec.NewLegacyAmino() + AuthzModuleCdc = codec.NewAminoCodec(Amino) +) + +func init() { + cryptocodec.RegisterCrypto(Amino) + codec.RegisterEvidences(Amino) + sdk.RegisterLegacyAminoCodec(Amino) +} + +func TestMessageAuthzSerialization(t *testing.T, msg sdk.Msg) { + someDate := time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC) + const ( + mockGranter string = "cosmos1abc" + mockGrantee string = "cosmos1xyz" + ) + + var ( + mockMsgGrant authz.MsgGrant + mockMsgRevoke authz.MsgRevoke + mockMsgExec authz.MsgExec + ) + + // Authz: Grant Msg + typeURL := sdk.MsgTypeURL(msg) + later := someDate.Add(time.Hour) + grant, err := authz.NewGrant(authz.NewGenericAuthorization(typeURL), later) + require.NoError(t, err) + + msgGrant := authz.MsgGrant{Granter: mockGranter, Grantee: mockGrantee, Grant: grant} + msgGrantBytes := json.RawMessage(sdk.MustSortJSON(AuthzModuleCdc.MustMarshalJSON(&msgGrant))) + err = AuthzModuleCdc.UnmarshalJSON(msgGrantBytes, &mockMsgGrant) + require.NoError(t, err) + + // Authz: Revoke Msg + msgRevoke := authz.MsgRevoke{Granter: mockGranter, Grantee: mockGrantee, MsgTypeUrl: typeURL} + msgRevokeByte := json.RawMessage(sdk.MustSortJSON(AuthzModuleCdc.MustMarshalJSON(&msgRevoke))) + err = AuthzModuleCdc.UnmarshalJSON(msgRevokeByte, &mockMsgRevoke) + require.NoError(t, err) + + // Authz: Exec Msg + msgAny, err := cdctypes.NewAnyWithValue(msg) + require.NoError(t, err) + msgExec := authz.MsgExec{Grantee: mockGrantee, Msgs: []*cdctypes.Any{msgAny}} + execMsgByte := json.RawMessage(sdk.MustSortJSON(AuthzModuleCdc.MustMarshalJSON(&msgExec))) + err = AuthzModuleCdc.UnmarshalJSON(execMsgByte, &mockMsgExec) + require.NoError(t, err) + require.Equal(t, msgExec.Msgs[0].Value, mockMsgExec.Msgs[0].Value) +} diff --git a/x/tokenfactory/types/authorityMetadata.go b/x/tokenfactory/types/authorityMetadata.go new file mode 100644 index 000000000..b45bffcab --- /dev/null +++ b/x/tokenfactory/types/authorityMetadata.go @@ -0,0 +1,15 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (metadata DenomAuthorityMetadata) Validate() error { + if metadata.Admin != "" { + _, err := sdk.AccAddressFromBech32(metadata.Admin) + if err != nil { + return err + } + } + return nil +} diff --git a/x/tokenfactory/types/authorityMetadata.pb.go b/x/tokenfactory/types/authorityMetadata.pb.go new file mode 100644 index 000000000..d36073fc6 --- /dev/null +++ b/x/tokenfactory/types/authorityMetadata.pb.go @@ -0,0 +1,352 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tokenfactory/v1beta1/authorityMetadata.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// DenomAuthorityMetadata specifies metadata for addresses that have specific +// capabilities over a token factory denom. Right now there is only one Admin +// permission, but is planned to be extended to the future. +type DenomAuthorityMetadata struct { + // Can be empty for no admin, or a valid osmosis address + Admin string `protobuf:"bytes,1,opt,name=admin,proto3" json:"admin,omitempty" yaml:"admin"` +} + +func (m *DenomAuthorityMetadata) Reset() { *m = DenomAuthorityMetadata{} } +func (m *DenomAuthorityMetadata) String() string { return proto.CompactTextString(m) } +func (*DenomAuthorityMetadata) ProtoMessage() {} +func (*DenomAuthorityMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_1b00b40c54827026, []int{0} +} +func (m *DenomAuthorityMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DenomAuthorityMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DenomAuthorityMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DenomAuthorityMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_DenomAuthorityMetadata.Merge(m, src) +} +func (m *DenomAuthorityMetadata) XXX_Size() int { + return m.Size() +} +func (m *DenomAuthorityMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_DenomAuthorityMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_DenomAuthorityMetadata proto.InternalMessageInfo + +func (m *DenomAuthorityMetadata) GetAdmin() string { + if m != nil { + return m.Admin + } + return "" +} + +func init() { + proto.RegisterType((*DenomAuthorityMetadata)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.DenomAuthorityMetadata") +} + +func init() { + proto.RegisterFile("tokenfactory/v1beta1/authorityMetadata.proto", fileDescriptor_1b00b40c54827026) +} + +var fileDescriptor_1b00b40c54827026 = []byte{ + // 242 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x29, 0xc9, 0xcf, 0x4e, + 0xcd, 0x4b, 0x4b, 0x4c, 0x2e, 0xc9, 0x2f, 0xaa, 0xd4, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, + 0xd4, 0x4f, 0x2c, 0x2d, 0xc9, 0xc8, 0x2f, 0xca, 0x2c, 0xa9, 0xf4, 0x4d, 0x2d, 0x49, 0x4c, 0x49, + 0x2c, 0x49, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xd2, 0x2a, 0x2c, 0x4d, 0x2c, 0x4e, 0x2c, + 0xca, 0x49, 0x4c, 0x2a, 0xd6, 0x83, 0x30, 0xf3, 0xf2, 0x53, 0x52, 0xf5, 0x90, 0xcd, 0xd0, 0x83, + 0x9a, 0x21, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0xd6, 0xa6, 0x0f, 0x62, 0x41, 0x4c, 0x90, 0x92, + 0x4b, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0xd6, 0x4f, 0x4a, 0x2c, 0x4e, 0x85, 0x5b, 0x97, 0x9c, 0x9f, + 0x99, 0x07, 0x91, 0x57, 0x72, 0xe3, 0x12, 0x73, 0x49, 0xcd, 0xcb, 0xcf, 0x75, 0x44, 0x77, 0x81, + 0x90, 0x1a, 0x17, 0x6b, 0x62, 0x4a, 0x6e, 0x66, 0x9e, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xa7, 0x93, + 0xc0, 0xa7, 0x7b, 0xf2, 0x3c, 0x95, 0x89, 0xb9, 0x39, 0x56, 0x4a, 0x60, 0x61, 0xa5, 0x20, 0x88, + 0xb4, 0x15, 0xcb, 0x8b, 0x05, 0xf2, 0x8c, 0x4e, 0xfe, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, + 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, + 0x2c, 0xc7, 0x10, 0x65, 0x9a, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x8f, + 0xf0, 0x8e, 0x3e, 0xc2, 0x3b, 0xfa, 0x15, 0xfa, 0x28, 0x81, 0x52, 0x52, 0x59, 0x90, 0x5a, 0x9c, + 0xc4, 0x06, 0x76, 0x9f, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x01, 0x36, 0x25, 0x67, 0x31, 0x01, + 0x00, 0x00, +} + +func (this *DenomAuthorityMetadata) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*DenomAuthorityMetadata) + if !ok { + that2, ok := that.(DenomAuthorityMetadata) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Admin != that1.Admin { + return false + } + return true +} +func (m *DenomAuthorityMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DenomAuthorityMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DenomAuthorityMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintAuthorityMetadata(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintAuthorityMetadata(dAtA []byte, offset int, v uint64) int { + offset -= sovAuthorityMetadata(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *DenomAuthorityMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovAuthorityMetadata(uint64(l)) + } + return n +} + +func sovAuthorityMetadata(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAuthorityMetadata(x uint64) (n int) { + return sovAuthorityMetadata(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *DenomAuthorityMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DenomAuthorityMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DenomAuthorityMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthorityMetadata + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthorityMetadata + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthorityMetadata(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthorityMetadata + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAuthorityMetadata(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAuthorityMetadata + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAuthorityMetadata + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAuthorityMetadata + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAuthorityMetadata = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAuthorityMetadata = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAuthorityMetadata = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tokenfactory/types/authzcodec/codec.go b/x/tokenfactory/types/authzcodec/codec.go new file mode 100644 index 000000000..366e337a1 --- /dev/null +++ b/x/tokenfactory/types/authzcodec/codec.go @@ -0,0 +1,24 @@ +package authzcodec + +// Note: this file is a copy from authz/codec in 0.46 so we can be compatible with 0.45 + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + Amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewAminoCodec(Amino) +) + +func init() { + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + sdk.RegisterLegacyAminoCodec(Amino) + cryptocodec.RegisterCrypto(Amino) + codec.RegisterEvidences(Amino) + + Amino.Seal() +} diff --git a/x/tokenfactory/types/codec.go b/x/tokenfactory/types/codec.go new file mode 100644 index 000000000..68b014e8f --- /dev/null +++ b/x/tokenfactory/types/codec.go @@ -0,0 +1,47 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + // authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" + + // this line is used by starport scaffolding # 1 + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgCreateDenom{}, "quasar/tokenfactory/create-denom", nil) + cdc.RegisterConcrete(&MsgMint{}, "quasar/tokenfactory/mint", nil) + cdc.RegisterConcrete(&MsgBurn{}, "quasar/tokenfactory/burn", nil) + cdc.RegisterConcrete(&MsgChangeAdmin{}, "quasar/tokenfactory/change-admin", nil) +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgCreateDenom{}, + &MsgMint{}, + &MsgBurn{}, + &MsgChangeAdmin{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) +) + +func init() { + RegisterCodec(amino) + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + // Note: these 3 are inlines from authz/codec in 0.46 so we can be compatible with 0.45 + sdk.RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) + codec.RegisterEvidences(amino) + + amino.Seal() +} diff --git a/x/tokenfactory/types/denoms.go b/x/tokenfactory/types/denoms.go new file mode 100644 index 000000000..09f524774 --- /dev/null +++ b/x/tokenfactory/types/denoms.go @@ -0,0 +1,84 @@ +package types + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const ( + ModuleDenomPrefix = "factory" + // See the TokenFactory readme for a derivation of these. + // TL;DR, MaxSubdenomLength + MaxHrpLength = 60 comes from SDK max denom length = 128 + // and the structure of tokenfactory denoms. + MaxSubdenomLength = 44 + MaxHrpLength = 16 + // MaxCreatorLength = 59 + MaxHrpLength + MaxCreatorLength = 59 + MaxHrpLength +) + +// GetTokenDenom constructs a denom string for tokens created by tokenfactory +// based on an input creator address and a subdenom +// The denom constructed is factory/{creator}/{subdenom} +func GetTokenDenom(creator, subdenom string) (string, error) { + if len(subdenom) > MaxSubdenomLength { + return "", ErrSubdenomTooLong + } + if len(creator) > MaxCreatorLength { + return "", ErrCreatorTooLong + } + if strings.Contains(creator, "/") { + return "", ErrInvalidCreator + } + denom := strings.Join([]string{ModuleDenomPrefix, creator, subdenom}, "/") + return denom, sdk.ValidateDenom(denom) +} + +// DeconstructDenom takes a token denom string and verifies that it is a valid +// denom of the tokenfactory module, and is of the form `factory/{creator}/{subdenom}` +// If valid, it returns the creator address and subdenom +func DeconstructDenom(denom string) (creator string, subdenom string, err error) { + err = sdk.ValidateDenom(denom) + if err != nil { + return "", "", err + } + + strParts := strings.Split(denom, "/") + if len(strParts) < 3 { + return "", "", sdkerrors.Wrapf(ErrInvalidDenom, "not enough parts of denom %s", denom) + } + + if strParts[0] != ModuleDenomPrefix { + return "", "", sdkerrors.Wrapf(ErrInvalidDenom, "denom prefix is incorrect. Is: %s. Should be: %s", strParts[0], ModuleDenomPrefix) + } + + creator = strParts[1] + creatorAddr, err := sdk.AccAddressFromBech32(creator) + if err != nil { + return "", "", sdkerrors.Wrapf(ErrInvalidDenom, "Invalid creator address (%s)", err) + } + + // Handle the case where a denom has a slash in its subdenom. For example, + // when we did the split, we'd turn factory/accaddr/atomderivative/sikka into ["factory", "accaddr", "atomderivative", "sikka"] + // So we have to join [2:] with a "/" as the delimiter to get back the correct subdenom which should be "atomderivative/sikka" + subdenom = strings.Join(strParts[2:], "/") + + return creatorAddr.String(), subdenom, nil +} + +/* +// NewTokenFactoryDenomMintCoinsRestriction creates and returns a BankMintingRestrictionFn that only allows minting of +// valid tokenfactory denoms +func NewTokenFactoryDenomMintCoinsRestriction() bankkeeper.BankMintingRestrictionFn { + return func(ctx sdk.Context, coinsToMint sdk.Coins) error { + for _, coin := range coinsToMint { + _, _, err := DeconstructDenom(coin.Denom) + if err != nil { + return fmt.Errorf("does not have permission to mint %s", coin.Denom) + } + } + return nil + } +} +*/ diff --git a/x/tokenfactory/types/denoms_test.go b/x/tokenfactory/types/denoms_test.go new file mode 100644 index 000000000..6f5f7f221 --- /dev/null +++ b/x/tokenfactory/types/denoms_test.go @@ -0,0 +1,130 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + cmd "github.com/quasarlabs/quasarnode/cmd/quasarnoded/cmd" + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +func TestDeconstructDenom(t *testing.T) { + cmd.InitTestConfig() + for _, tc := range []struct { + desc string + denom string + expectedSubdenom string + err error + }{ + { + desc: "empty is invalid", + denom: "", + err: types.ErrInvalidDenom, + }, + { + desc: "normal", + denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + expectedSubdenom: "bitcoin", + }, + { + desc: "multiple slashes in subdenom", + denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin/1", + expectedSubdenom: "bitcoin/1", + }, + { + desc: "no subdenom", + denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/", + expectedSubdenom: "", + }, + { + desc: "incorrect prefix", + denom: "ibc/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + err: types.ErrInvalidDenom, + }, + { + desc: "subdenom of only slashes", + denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/////", + expectedSubdenom: "////", + }, + { + desc: "too long name", + denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/adsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsf", + err: types.ErrInvalidDenom, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + expectedCreator := "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec" + creator, subdenom, err := types.DeconstructDenom(tc.denom) + if tc.err != nil { + require.ErrorContains(t, err, tc.err.Error()) + } else { + require.NoError(t, err) + require.Equal(t, expectedCreator, creator) + require.Equal(t, tc.expectedSubdenom, subdenom) + } + }) + } +} + +func TestGetTokenDenom(t *testing.T) { + cmd.InitTestConfig() + for _, tc := range []struct { + desc string + creator string + subdenom string + valid bool + }{ + { + desc: "normal", + creator: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + subdenom: "bitcoin", + valid: true, + }, + { + desc: "multiple slashes in subdenom", + creator: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + subdenom: "bitcoin/1", + valid: true, + }, + { + desc: "no subdenom", + creator: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + subdenom: "", + valid: true, + }, + { + desc: "subdenom of only slashes", + creator: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + subdenom: "/////", + valid: true, + }, + { + desc: "too long name", + creator: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + subdenom: "adsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsf", + valid: false, + }, + { + desc: "subdenom is exactly max length", + creator: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + subdenom: "bitcoinfsadfsdfeadfsafwefsefsefsdfsdafasefsf", + valid: true, + }, + { + desc: "creator is exactly max length", + creator: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwecjhgjhgkhjklhkjhkjhgjhgjgjghelu", + subdenom: "bitcoin", + valid: true, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + _, err := types.GetTokenDenom(tc.creator, tc.subdenom) + if tc.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/x/tokenfactory/types/errors.go b/x/tokenfactory/types/errors.go new file mode 100644 index 000000000..2c3708fa6 --- /dev/null +++ b/x/tokenfactory/types/errors.go @@ -0,0 +1,23 @@ +package types + +// DONTCOVER + +import ( + fmt "fmt" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// x/tokenfactory module sentinel errors +var ( + ErrDenomExists = sdkerrors.Register(ModuleName, 2, "attempting to create a denom that already exists (has bank metadata)") + ErrUnauthorized = sdkerrors.Register(ModuleName, 3, "unauthorized account") + ErrInvalidDenom = sdkerrors.Register(ModuleName, 4, "invalid denom") + ErrInvalidCreator = sdkerrors.Register(ModuleName, 5, "invalid creator") + ErrInvalidAuthorityMetadata = sdkerrors.Register(ModuleName, 6, "invalid authority metadata") + ErrInvalidGenesis = sdkerrors.Register(ModuleName, 7, "invalid genesis") + ErrSubdenomTooLong = sdkerrors.Register(ModuleName, 8, fmt.Sprintf("subdenom too long, max length is %d bytes", MaxSubdenomLength)) + ErrCreatorTooLong = sdkerrors.Register(ModuleName, 9, fmt.Sprintf("creator too long, max length is %d bytes", MaxCreatorLength)) + ErrBurnFromModuleAccount = sdkerrors.Register(ModuleName, 10, "burning from Module Account is not allowed") + ErrDenomDoesNotExist = sdkerrors.Register(ModuleName, 11, "denom does not exist") +) diff --git a/x/tokenfactory/types/events.go b/x/tokenfactory/types/events.go new file mode 100644 index 000000000..cdacafbf3 --- /dev/null +++ b/x/tokenfactory/types/events.go @@ -0,0 +1,17 @@ +package types + +// event types +const ( + AttributeAmount = "amount" + AttributeMsgSender = "sender" + AttributeCreator = "creator" + AttributeSubdenom = "subdenom" + AttributeNewTokenDenom = "new_token_denom" + AttributeMintToAddress = "mint_to_address" + AttributeBurnFromAddress = "burn_from_address" + AttributeTransferFromAddress = "transfer_from_address" + AttributeTransferToAddress = "transfer_to_address" + AttributeDenom = "denom" + AttributeNewAdmin = "new_admin" + AttributeDenomMetadata = "denom_metadata" +) diff --git a/x/tokenfactory/types/expected_keepers.go b/x/tokenfactory/types/expected_keepers.go new file mode 100644 index 000000000..ca2e31575 --- /dev/null +++ b/x/tokenfactory/types/expected_keepers.go @@ -0,0 +1,33 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +type BankKeeper interface { + // Methods imported from bank should be defined here + GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool) + SetDenomMetaData(ctx sdk.Context, denomMetaData banktypes.Metadata) + + HasSupply(ctx sdk.Context, denom string) bool + + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool +} + +type AccountKeeper interface { + SetModuleAccount(ctx sdk.Context, macc authtypes.ModuleAccountI) + GetAccount(sdk.Context, sdk.AccAddress) authtypes.AccountI +} + +// CommunityPoolKeeper defines the contract needed to be fulfilled for community pool interactions. +type CommunityPoolKeeper interface { + FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error +} diff --git a/x/tokenfactory/types/genesis.go b/x/tokenfactory/types/genesis.go new file mode 100644 index 000000000..b1ba181fa --- /dev/null +++ b/x/tokenfactory/types/genesis.go @@ -0,0 +1,51 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// this line is used by starport scaffolding # genesis/types/import + +// DefaultIndex is the default capability global index +const DefaultIndex uint64 = 1 + +// DefaultGenesis returns the default Capability genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + FactoryDenoms: []GenesisDenom{}, + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + err := gs.Params.Validate() + if err != nil { + return err + } + + seenDenoms := map[string]bool{} + + for _, denom := range gs.GetFactoryDenoms() { + if seenDenoms[denom.GetDenom()] { + return sdkerrors.Wrapf(ErrInvalidGenesis, "duplicate denom: %s", denom.GetDenom()) + } + seenDenoms[denom.GetDenom()] = true + + _, _, err := DeconstructDenom(denom.GetDenom()) + if err != nil { + return err + } + + if denom.AuthorityMetadata.Admin != "" { + _, err = sdk.AccAddressFromBech32(denom.AuthorityMetadata.Admin) + if err != nil { + return sdkerrors.Wrapf(ErrInvalidAuthorityMetadata, "Invalid admin address (%s)", err) + } + } + } + + return nil +} diff --git a/x/tokenfactory/types/genesis.pb.go b/x/tokenfactory/types/genesis.pb.go new file mode 100644 index 000000000..9124f2060 --- /dev/null +++ b/x/tokenfactory/types/genesis.pb.go @@ -0,0 +1,649 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tokenfactory/v1beta1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the tokenfactory module's genesis state. +type GenesisState struct { + // params defines the paramaters of the module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + FactoryDenoms []GenesisDenom `protobuf:"bytes,2,rep,name=factory_denoms,json=factoryDenoms,proto3" json:"factory_denoms" yaml:"factory_denoms"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_873314f411151e56, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetFactoryDenoms() []GenesisDenom { + if m != nil { + return m.FactoryDenoms + } + return nil +} + +// GenesisDenom defines a tokenfactory denom that is defined within genesis +// state. The structure contains DenomAuthorityMetadata which defines the +// denom's admin. +type GenesisDenom struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` + AuthorityMetadata DenomAuthorityMetadata `protobuf:"bytes,2,opt,name=authority_metadata,json=authorityMetadata,proto3" json:"authority_metadata" yaml:"authority_metadata"` +} + +func (m *GenesisDenom) Reset() { *m = GenesisDenom{} } +func (m *GenesisDenom) String() string { return proto.CompactTextString(m) } +func (*GenesisDenom) ProtoMessage() {} +func (*GenesisDenom) Descriptor() ([]byte, []int) { + return fileDescriptor_873314f411151e56, []int{1} +} +func (m *GenesisDenom) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisDenom) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisDenom.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisDenom) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisDenom.Merge(m, src) +} +func (m *GenesisDenom) XXX_Size() int { + return m.Size() +} +func (m *GenesisDenom) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisDenom.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisDenom proto.InternalMessageInfo + +func (m *GenesisDenom) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *GenesisDenom) GetAuthorityMetadata() DenomAuthorityMetadata { + if m != nil { + return m.AuthorityMetadata + } + return DenomAuthorityMetadata{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.GenesisState") + proto.RegisterType((*GenesisDenom)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.GenesisDenom") +} + +func init() { + proto.RegisterFile("tokenfactory/v1beta1/genesis.proto", fileDescriptor_873314f411151e56) +} + +var fileDescriptor_873314f411151e56 = []byte{ + // 367 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2a, 0xc9, 0xcf, 0x4e, + 0xcd, 0x4b, 0x4b, 0x4c, 0x2e, 0xc9, 0x2f, 0xaa, 0xd4, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, + 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xd2, + 0x2a, 0x2c, 0x4d, 0x2c, 0x4e, 0x2c, 0xca, 0x49, 0x4c, 0x2a, 0xd6, 0x83, 0x30, 0xf3, 0xf2, 0x53, + 0x52, 0xf5, 0x90, 0x75, 0xea, 0x41, 0x75, 0x4a, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0xb5, 0xe9, + 0x83, 0x58, 0x10, 0x13, 0xa4, 0x74, 0xb0, 0xda, 0x92, 0x58, 0x5a, 0x92, 0x91, 0x5f, 0x94, 0x59, + 0x52, 0xe9, 0x9b, 0x5a, 0x92, 0x98, 0x92, 0x58, 0x92, 0x08, 0x55, 0xad, 0x88, 0x55, 0x75, 0x41, + 0x62, 0x51, 0x62, 0x2e, 0xd4, 0x49, 0x4a, 0x0f, 0x18, 0xb9, 0x78, 0xdc, 0x21, 0x8e, 0x0c, 0x2e, + 0x49, 0x2c, 0x49, 0x15, 0x0a, 0xe0, 0x62, 0x83, 0x28, 0x90, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x36, + 0x32, 0xd2, 0x23, 0xde, 0xd1, 0x7a, 0x01, 0x60, 0x9d, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, 0x04, + 0x41, 0xcd, 0x11, 0xaa, 0xe3, 0xe2, 0x83, 0xaa, 0x8b, 0x4f, 0x49, 0xcd, 0xcb, 0xcf, 0x2d, 0x96, + 0x60, 0x52, 0x60, 0xd6, 0xe0, 0x36, 0xb2, 0x20, 0xc5, 0x64, 0xa8, 0x1b, 0x5d, 0x40, 0x06, 0x38, + 0xc9, 0x82, 0xcc, 0xff, 0x74, 0x4f, 0x5e, 0xb4, 0x32, 0x31, 0x37, 0xc7, 0x4a, 0x09, 0xd5, 0x74, + 0xa5, 0x20, 0x5e, 0xa8, 0x80, 0x0b, 0x84, 0x7f, 0x19, 0xe1, 0x45, 0xb0, 0x88, 0x90, 0x1a, 0x17, + 0x2b, 0x58, 0x29, 0xd8, 0x87, 0x9c, 0x4e, 0x02, 0x9f, 0xee, 0xc9, 0xf3, 0x40, 0x4c, 0x02, 0x0b, + 0x2b, 0x05, 0x41, 0xa4, 0x85, 0xa6, 0x30, 0x72, 0x09, 0xc1, 0x83, 0x36, 0x3e, 0x17, 0x1a, 0xb6, + 0x12, 0x4c, 0xe0, 0x70, 0x71, 0x22, 0xc5, 0xf5, 0x60, 0x7b, 0x1d, 0xd1, 0x63, 0xc9, 0x49, 0x11, + 0xea, 0x0f, 0x49, 0x88, 0xed, 0x98, 0x76, 0x29, 0x05, 0x09, 0x62, 0xc4, 0xad, 0x15, 0xcb, 0x8b, + 0x05, 0xf2, 0x8c, 0x4e, 0xfe, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, + 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, + 0x9a, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x8f, 0x70, 0xa3, 0x3e, 0xc2, + 0x8d, 0xfa, 0x15, 0xfa, 0x28, 0x09, 0xa3, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x9c, 0x20, + 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x22, 0xf2, 0x13, 0x9a, 0xc9, 0x02, 0x00, 0x00, +} + +func (this *GenesisDenom) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*GenesisDenom) + if !ok { + that2, ok := that.(GenesisDenom) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Denom != that1.Denom { + return false + } + if !this.AuthorityMetadata.Equal(&that1.AuthorityMetadata) { + return false + } + return true +} +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FactoryDenoms) > 0 { + for iNdEx := len(m.FactoryDenoms) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FactoryDenoms[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *GenesisDenom) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisDenom) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisDenom) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.AuthorityMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.FactoryDenoms) > 0 { + for _, e := range m.FactoryDenoms { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *GenesisDenom) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.AuthorityMetadata.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FactoryDenoms", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FactoryDenoms = append(m.FactoryDenoms, GenesisDenom{}) + if err := m.FactoryDenoms[len(m.FactoryDenoms)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisDenom) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisDenom: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisDenom: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AuthorityMetadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.AuthorityMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tokenfactory/types/genesis_test.go b/x/tokenfactory/types/genesis_test.go new file mode 100644 index 000000000..29f0bdf70 --- /dev/null +++ b/x/tokenfactory/types/genesis_test.go @@ -0,0 +1,141 @@ +package types_test + +import ( + "github.com/quasarlabs/quasarnode/cmd/quasarnoded/cmd" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" +) + +func TestGenesisState_Validate(t *testing.T) { + cmd.InitTestConfig() + for _, tc := range []struct { + desc string + genState *types.GenesisState + valid bool + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + valid: true, + }, + { + desc: "valid genesis state", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec", + }, + }, + }, + }, + valid: true, + }, + { + desc: "different admin from creator", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "quasar1828z63g9wp3qwyn4p64adc3ungsv56ux5aacmu", + }, + }, + }, + }, + valid: true, + }, + { + desc: "empty admin", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + }, + }, + valid: true, + }, + { + desc: "no admin", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + }, + }, + }, + valid: true, + }, + { + desc: "invalid admin", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "moose", + }, + }, + }, + }, + valid: false, + }, + { + desc: "multiple denoms", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/litecoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + }, + }, + valid: true, + }, + { + desc: "duplicate denoms", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + { + Denom: "factory/quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + }, + }, + valid: false, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + if tc.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/x/tokenfactory/types/keys.go b/x/tokenfactory/types/keys.go new file mode 100644 index 000000000..fac4a6e39 --- /dev/null +++ b/x/tokenfactory/types/keys.go @@ -0,0 +1,49 @@ +package types + +import ( + "strings" +) + +const ( + // ModuleName defines the module name + ModuleName = "tokenfactory" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey is the message route for slashing + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key + QuerierRoute = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_tokenfactory" +) + +// KeySeparator is used to combine parts of the keys in the store +const KeySeparator = "|" + +var ( + DenomAuthorityMetadataKey = "authoritymetadata" + DenomsPrefixKey = "denoms" + CreatorPrefixKey = "creator" + AdminPrefixKey = "admin" +) + +// GetDenomPrefixStore returns the store prefix where all the data associated with a specific denom +// is stored +func GetDenomPrefixStore(denom string) []byte { + return []byte(strings.Join([]string{DenomsPrefixKey, denom, ""}, KeySeparator)) +} + +// GetCreatorsPrefix returns the store prefix where the list of the denoms created by a specific +// creator are stored +func GetCreatorPrefix(creator string) []byte { + return []byte(strings.Join([]string{CreatorPrefixKey, creator, ""}, KeySeparator)) +} + +// GetCreatorsPrefix returns the store prefix where a list of all creator addresses are stored +func GetCreatorsPrefix() []byte { + return []byte(strings.Join([]string{CreatorPrefixKey, ""}, KeySeparator)) +} diff --git a/x/tokenfactory/types/msgs.go b/x/tokenfactory/types/msgs.go new file mode 100644 index 000000000..42b857cb5 --- /dev/null +++ b/x/tokenfactory/types/msgs.go @@ -0,0 +1,216 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// constants +const ( + TypeMsgCreateDenom = "create_denom" + TypeMsgMint = "tf_mint" + TypeMsgBurn = "tf_burn" + TypeMsgChangeAdmin = "change_admin" + TypeMsgSetDenomMetadata = "set_denom_metadata" +) + +var _ sdk.Msg = &MsgCreateDenom{} + +// NewMsgCreateDenom creates a msg to create a new denom +func NewMsgCreateDenom(sender, subdenom string) *MsgCreateDenom { + return &MsgCreateDenom{ + Sender: sender, + Subdenom: subdenom, + } +} + +func (m MsgCreateDenom) Route() string { return RouterKey } +func (m MsgCreateDenom) Type() string { return TypeMsgCreateDenom } +func (m MsgCreateDenom) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + _, err = GetTokenDenom(m.Sender, m.Subdenom) + if err != nil { + return sdkerrors.Wrap(ErrInvalidDenom, err.Error()) + } + + return nil +} + +func (m MsgCreateDenom) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgCreateDenom) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} + +var _ sdk.Msg = &MsgMint{} + +// NewMsgMint creates a message to mint tokens +func NewMsgMint(sender string, amount sdk.Coin) *MsgMint { + return &MsgMint{ + Sender: sender, + Amount: amount, + } +} + +func NewMsgMintTo(sender string, amount sdk.Coin, mintToAddress string) *MsgMint { + return &MsgMint{ + Sender: sender, + Amount: amount, + MintToAddress: mintToAddress, + } +} +func (m MsgMint) Route() string { return RouterKey } +func (m MsgMint) Type() string { return TypeMsgMint } +func (m MsgMint) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + if !m.Amount.IsValid() || m.Amount.Amount.Equal(sdk.ZeroInt()) { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, m.Amount.String()) + } + + return nil +} + +func (m MsgMint) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgMint) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} + +var _ sdk.Msg = &MsgBurn{} + +// NewMsgBurn creates a message to burn tokens +func NewMsgBurn(sender string, amount sdk.Coin) *MsgBurn { + return &MsgBurn{ + Sender: sender, + Amount: amount, + } +} + +// NewMsgBurn creates a message to burn tokens +func NewMsgBurnFrom(sender string, amount sdk.Coin, burnFromAddress string) *MsgBurn { + return &MsgBurn{ + Sender: sender, + Amount: amount, + BurnFromAddress: burnFromAddress, + } +} + +func (m MsgBurn) Route() string { return RouterKey } +func (m MsgBurn) Type() string { return TypeMsgBurn } +func (m MsgBurn) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + if !m.Amount.IsValid() || m.Amount.Amount.Equal(sdk.ZeroInt()) { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, m.Amount.String()) + } + + return nil +} + +func (m MsgBurn) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgBurn) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} + +var _ sdk.Msg = &MsgChangeAdmin{} + +// NewMsgChangeAdmin creates a message to burn tokens +func NewMsgChangeAdmin(sender, denom, newAdmin string) *MsgChangeAdmin { + return &MsgChangeAdmin{ + Sender: sender, + Denom: denom, + NewAdmin: newAdmin, + } +} + +func (m MsgChangeAdmin) Route() string { return RouterKey } +func (m MsgChangeAdmin) Type() string { return TypeMsgChangeAdmin } +func (m MsgChangeAdmin) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + _, err = sdk.AccAddressFromBech32(m.NewAdmin) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid address (%s)", err) + } + + _, _, err = DeconstructDenom(m.Denom) + if err != nil { + return err + } + + return nil +} + +func (m MsgChangeAdmin) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgChangeAdmin) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} + +var _ sdk.Msg = &MsgSetDenomMetadata{} + +// NewMsgChangeAdmin creates a message to burn tokens +func NewMsgSetDenomMetadata(sender string, metadata banktypes.Metadata) *MsgSetDenomMetadata { + return &MsgSetDenomMetadata{ + Sender: sender, + Metadata: metadata, + } +} + +func (m MsgSetDenomMetadata) Route() string { return RouterKey } +func (m MsgSetDenomMetadata) Type() string { return TypeMsgSetDenomMetadata } +func (m MsgSetDenomMetadata) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + err = m.Metadata.Validate() + if err != nil { + return err + } + + _, _, err = DeconstructDenom(m.Metadata.Base) + if err != nil { + return err + } + + return nil +} + +func (m MsgSetDenomMetadata) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgSetDenomMetadata) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} diff --git a/x/tokenfactory/types/msgs_test.go b/x/tokenfactory/types/msgs_test.go new file mode 100644 index 000000000..a79ad3ac7 --- /dev/null +++ b/x/tokenfactory/types/msgs_test.go @@ -0,0 +1,451 @@ +package types_test + +import ( + fmt "fmt" + "testing" + + // "github.com/CosmosTokenFactory/token-factory/app/apptesting" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/quasarlabs/quasarnode/x/tokenfactory/testhelpers" + "github.com/quasarlabs/quasarnode/x/tokenfactory/types" + "github.com/stretchr/testify/require" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/tendermint/tendermint/crypto/ed25519" +) + +// // Test authz serialize and de-serializes for tokenfactory msg. +func TestAuthzMsg(t *testing.T) { + t.Skip("TODO: figure out how to register authz interfaces for tests") + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()).String() + coin := sdk.NewCoin("denom", sdk.NewInt(1)) + + testCases := []struct { + name string + msg sdk.Msg + }{ + { + name: "MsgCreateDenom", + msg: &types.MsgCreateDenom{ + Sender: addr1, + Subdenom: "valoper1xyz", + }, + }, + { + name: "MsgBurn", + msg: &types.MsgBurn{ + Sender: addr1, + Amount: coin, + }, + }, + { + name: "MsgMint", + msg: &types.MsgMint{ + Sender: addr1, + Amount: coin, + }, + }, + { + name: "MsgChangeAdmin", + msg: &types.MsgChangeAdmin{ + Sender: addr1, + Denom: "denom", + NewAdmin: "osmo1q8tq5qhrhw6t970egemuuwywhlhpnmdmts6xnu", + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + testhelpers.TestMessageAuthzSerialization(t, tc.msg) + }) + } +} + +// TestMsgCreateDenom tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgCreateDenom(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + + // make a proper createDenom message + createMsg := func(after func(msg types.MsgCreateDenom) types.MsgCreateDenom) types.MsgCreateDenom { + properMsg := *types.NewMsgCreateDenom( + addr1.String(), + "bitcoin", + ) + + return after(properMsg) + } + + // validate createDenom message was created as intended + msg := createMsg(func(msg types.MsgCreateDenom) types.MsgCreateDenom { + return msg + }) + require.Equal(t, msg.Route(), types.RouterKey) + require.Equal(t, msg.Type(), "create_denom") + signers := msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg types.MsgCreateDenom + expectPass bool + }{ + { + name: "proper msg", + msg: createMsg(func(msg types.MsgCreateDenom) types.MsgCreateDenom { + return msg + }), + expectPass: true, + }, + { + name: "empty sender", + msg: createMsg(func(msg types.MsgCreateDenom) types.MsgCreateDenom { + msg.Sender = "" + return msg + }), + expectPass: false, + }, + { + name: "invalid subdenom", + msg: createMsg(func(msg types.MsgCreateDenom) types.MsgCreateDenom { + msg.Subdenom = "thissubdenomismuchtoolongasdkfjaasdfdsafsdlkfnmlksadmflksmdlfmlsakmfdsafasdfasdf" + return msg + }), + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg.ValidateBasic(), "test: %v", test.name) + } + } +} + +// TestMsgMint tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgMint(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + + // make a proper mint message + createMsg := func(after func(msg types.MsgMint) types.MsgMint) types.MsgMint { + properMsg := *types.NewMsgMint( + addr1.String(), + sdk.NewCoin("bitcoin", sdk.NewInt(500000000)), + ) + + return after(properMsg) + } + + // validate mint message was created as intended + msg := createMsg(func(msg types.MsgMint) types.MsgMint { + return msg + }) + require.Equal(t, msg.Route(), types.RouterKey) + require.Equal(t, msg.Type(), "tf_mint") + signers := msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg types.MsgMint + expectPass bool + }{ + { + name: "proper msg", + msg: createMsg(func(msg types.MsgMint) types.MsgMint { + return msg + }), + expectPass: true, + }, + { + name: "empty sender", + msg: createMsg(func(msg types.MsgMint) types.MsgMint { + msg.Sender = "" + return msg + }), + expectPass: false, + }, + { + name: "zero amount", + msg: createMsg(func(msg types.MsgMint) types.MsgMint { + msg.Amount = sdk.NewCoin("bitcoin", sdk.ZeroInt()) + return msg + }), + expectPass: false, + }, + { + name: "negative amount", + msg: createMsg(func(msg types.MsgMint) types.MsgMint { + msg.Amount.Amount = sdk.NewInt(-10000000) + return msg + }), + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg.ValidateBasic(), "test: %v", test.name) + } + } +} + +// TestMsgBurn tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgBurn(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + + // make a proper burn message + baseMsg := types.NewMsgBurn( + addr1.String(), + sdk.NewCoin("bitcoin", sdk.NewInt(500000000)), + ) + + // validate burn message was created as intended + require.Equal(t, baseMsg.Route(), types.RouterKey) + require.Equal(t, baseMsg.Type(), "tf_burn") + signers := baseMsg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg func() *types.MsgBurn + expectPass bool + }{ + { + name: "proper msg", + msg: func() *types.MsgBurn { + msg := baseMsg + return msg + }, + expectPass: true, + }, + { + name: "empty sender", + msg: func() *types.MsgBurn { + msg := baseMsg + msg.Sender = "" + return msg + }, + expectPass: false, + }, + { + name: "zero amount", + msg: func() *types.MsgBurn { + msg := baseMsg + msg.Amount.Amount = sdk.ZeroInt() + return msg + }, + expectPass: false, + }, + { + name: "negative amount", + msg: func() *types.MsgBurn { + msg := baseMsg + msg.Amount.Amount = sdk.NewInt(-10000000) + return msg + }, + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg().ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg().ValidateBasic(), "test: %v", test.name) + } + } +} + +// TestMsgChangeAdmin tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgChangeAdmin(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + pk2 := ed25519.GenPrivKey().PubKey() + addr2 := sdk.AccAddress(pk2.Address()) + tokenFactoryDenom := fmt.Sprintf("factory/%s/bitcoin", addr1.String()) + + // make a proper changeAdmin message + baseMsg := types.NewMsgChangeAdmin( + addr1.String(), + tokenFactoryDenom, + addr2.String(), + ) + + // validate changeAdmin message was created as intended + require.Equal(t, baseMsg.Route(), types.RouterKey) + require.Equal(t, baseMsg.Type(), "change_admin") + signers := baseMsg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg func() *types.MsgChangeAdmin + expectPass bool + }{ + { + name: "proper msg", + msg: func() *types.MsgChangeAdmin { + msg := baseMsg + return msg + }, + expectPass: true, + }, + { + name: "empty sender", + msg: func() *types.MsgChangeAdmin { + msg := baseMsg + msg.Sender = "" + return msg + }, + expectPass: false, + }, + { + name: "empty newAdmin", + msg: func() *types.MsgChangeAdmin { + msg := baseMsg + msg.NewAdmin = "" + return msg + }, + expectPass: false, + }, + { + name: "invalid denom", + msg: func() *types.MsgChangeAdmin { + msg := baseMsg + msg.Denom = "bitcoin" + return msg + }, + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg().ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg().ValidateBasic(), "test: %v", test.name) + } + } +} + +// TestMsgSetDenomMetadata tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgSetDenomMetadata(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + tokenFactoryDenom := fmt.Sprintf("factory/%s/bitcoin", addr1.String()) + denomMetadata := banktypes.Metadata{ + Description: "nakamoto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: tokenFactoryDenom, + Exponent: 0, + }, + { + Denom: "sats", + Exponent: 6, + }, + }, + Display: "sats", + Base: tokenFactoryDenom, + Name: "bitcoin", + Symbol: "BTC", + } + invalidDenomMetadata := banktypes.Metadata{ + Description: "nakamoto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "bitcoin", + Exponent: 0, + }, + { + Denom: "sats", + Exponent: 6, + }, + }, + Display: "sats", + Base: "bitcoin", + Name: "bitcoin", + Symbol: "BTC", + } + + // make a proper setDenomMetadata message + baseMsg := types.NewMsgSetDenomMetadata( + addr1.String(), + denomMetadata, + ) + + // validate setDenomMetadata message was created as intended + require.Equal(t, baseMsg.Route(), types.RouterKey) + require.Equal(t, baseMsg.Type(), "set_denom_metadata") + signers := baseMsg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg func() *types.MsgSetDenomMetadata + expectPass bool + }{ + { + name: "proper msg", + msg: func() *types.MsgSetDenomMetadata { + msg := baseMsg + return msg + }, + expectPass: true, + }, + { + name: "empty sender", + msg: func() *types.MsgSetDenomMetadata { + msg := baseMsg + msg.Sender = "" + return msg + }, + expectPass: false, + }, + { + name: "invalid metadata", + msg: func() *types.MsgSetDenomMetadata { + msg := baseMsg + msg.Metadata.Name = "" + return msg + }, + + expectPass: false, + }, + { + name: "invalid base", + msg: func() *types.MsgSetDenomMetadata { + msg := baseMsg + msg.Metadata = invalidDenomMetadata + return msg + }, + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg().ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg().ValidateBasic(), "test: %v", test.name) + } + } +} diff --git a/x/tokenfactory/types/params.go b/x/tokenfactory/types/params.go new file mode 100644 index 000000000..b70acb179 --- /dev/null +++ b/x/tokenfactory/types/params.go @@ -0,0 +1,79 @@ +package types + +import ( + "fmt" + appparams "github.com/quasarlabs/quasarnode/app/params" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +var _ paramtypes.ParamSet = (*Params)(nil) + +// Parameter store keys. +var ( + KeyDenomCreationFee = []byte("DenomCreationFee") + KeyDenomCreationGasConsume = []byte("DenomCreationGasConsume") +) + +// ParamTable for gamm module. +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +func NewParams(denomCreationFee sdk.Coins) Params { + return Params{ + DenomCreationFee: denomCreationFee, + } +} + +// default gamm module parameters. +func DefaultParams() Params { + return Params{ + DenomCreationFee: sdk.NewCoins(sdk.NewInt64Coin(appparams.BaseCoinUnit, 500_000_000)), + DenomCreationGasConsume: 100_000_000, + } +} + +// validate params. +func (p Params) Validate() error { + if err := validateDenomCreationFee(p.DenomCreationFee); err != nil { + return err + } + + if err := validateDenomCreationFeeGasConsume(p.DenomCreationGasConsume); err != nil { + return err + } + + return nil +} + +// Implements params.ParamSet. +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyDenomCreationFee, &p.DenomCreationFee, validateDenomCreationFee), + paramtypes.NewParamSetPair(KeyDenomCreationGasConsume, &p.DenomCreationGasConsume, validateDenomCreationFeeGasConsume), + } +} + +func validateDenomCreationFee(i interface{}) error { + v, ok := i.(sdk.Coins) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.Validate() != nil { + return fmt.Errorf("invalid denom creation fee: %+v", i) + } + + return nil +} + +func validateDenomCreationFeeGasConsume(i interface{}) error { + _, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} diff --git a/x/tokenfactory/types/params.pb.go b/x/tokenfactory/types/params.pb.go new file mode 100644 index 000000000..8fb9ad4d7 --- /dev/null +++ b/x/tokenfactory/types/params.pb.go @@ -0,0 +1,381 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tokenfactory/v1beta1/params.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the parameters for the tokenfactory module. +type Params struct { + DenomCreationFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=denom_creation_fee,json=denomCreationFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"denom_creation_fee" yaml:"denom_creation_fee"` + // if denom_creation_fee is an empty array, then this field is used to add more gas consumption + // to the base cost. + // https://github.com/CosmWasm/token-factory/issues/11 + DenomCreationGasConsume uint64 `protobuf:"varint,2,opt,name=denom_creation_gas_consume,json=denomCreationGasConsume,proto3" json:"denom_creation_gas_consume,omitempty" yaml:"denom_creation_gas_consume"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_4d491a2fda25be4d, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetDenomCreationFee() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.DenomCreationFee + } + return nil +} + +func (m *Params) GetDenomCreationGasConsume() uint64 { + if m != nil { + return m.DenomCreationGasConsume + } + return 0 +} + +func init() { + proto.RegisterType((*Params)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.Params") +} + +func init() { proto.RegisterFile("tokenfactory/v1beta1/params.proto", fileDescriptor_4d491a2fda25be4d) } + +var fileDescriptor_4d491a2fda25be4d = []byte{ + // 356 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xc1, 0x4e, 0xea, 0x40, + 0x14, 0x86, 0x5b, 0xee, 0x0d, 0x8b, 0xde, 0xcd, 0x4d, 0x63, 0x22, 0xb0, 0x68, 0xa1, 0x2b, 0x34, + 0xda, 0x09, 0x1a, 0x37, 0x2e, 0x21, 0xd1, 0x15, 0xd1, 0xb0, 0x74, 0xd3, 0x9c, 0xb6, 0x43, 0x69, + 0xa0, 0x73, 0xb0, 0x33, 0x35, 0xf6, 0x11, 0xdc, 0xb9, 0xf2, 0x21, 0x7c, 0x12, 0x96, 0x2c, 0x5d, + 0x55, 0x03, 0x6f, 0xc0, 0x13, 0x18, 0x3a, 0xa3, 0x80, 0xb2, 0xea, 0x39, 0x39, 0xe7, 0xff, 0xce, + 0xdf, 0xf9, 0x8d, 0x96, 0xc0, 0x31, 0x65, 0x43, 0x08, 0x04, 0xa6, 0x39, 0x79, 0xe8, 0xf8, 0x54, + 0x40, 0x87, 0x4c, 0x21, 0x85, 0x84, 0xbb, 0xd3, 0x14, 0x05, 0x9a, 0xc7, 0xf7, 0x19, 0x70, 0x48, + 0x27, 0xe0, 0x73, 0x57, 0x96, 0x0c, 0x43, 0xea, 0x6e, 0x0b, 0x5d, 0x25, 0x6c, 0x1c, 0x44, 0x18, + 0x61, 0x29, 0x23, 0xeb, 0x4a, 0x12, 0x1a, 0x27, 0x7b, 0x8f, 0x40, 0x26, 0x46, 0x98, 0xc6, 0x22, + 0xef, 0x53, 0x01, 0x21, 0x08, 0x50, 0xdb, 0xf5, 0x00, 0x79, 0x82, 0xdc, 0x93, 0x18, 0xd9, 0xa8, + 0x91, 0x25, 0x3b, 0xe2, 0x03, 0xa7, 0xdf, 0x9c, 0x00, 0x63, 0x26, 0xe7, 0xce, 0x53, 0xc5, 0xa8, + 0xde, 0x96, 0xde, 0xcd, 0x17, 0xdd, 0x30, 0x43, 0xca, 0x30, 0xf1, 0x82, 0x94, 0x82, 0x88, 0x91, + 0x79, 0x43, 0x4a, 0x6b, 0x7a, 0xf3, 0x4f, 0xfb, 0xdf, 0x59, 0xdd, 0x55, 0xd8, 0x35, 0xe8, 0xcb, + 0xbc, 0xdb, 0xc3, 0x98, 0x75, 0xfb, 0xb3, 0xc2, 0xd6, 0x56, 0x85, 0x5d, 0xcf, 0x21, 0x99, 0x5c, + 0x3a, 0xbf, 0x11, 0xce, 0xeb, 0xbb, 0xdd, 0x8e, 0x62, 0x31, 0xca, 0x7c, 0x37, 0xc0, 0x44, 0x19, + 0x54, 0x9f, 0x53, 0x1e, 0x8e, 0x89, 0xc8, 0xa7, 0x94, 0x97, 0x34, 0x3e, 0xf8, 0x5f, 0x02, 0x7a, + 0x4a, 0x7f, 0x45, 0xa9, 0x39, 0x34, 0x1a, 0x3f, 0xa0, 0x11, 0x70, 0x2f, 0x40, 0xc6, 0xb3, 0x84, + 0xd6, 0x2a, 0x4d, 0xbd, 0xfd, 0xb7, 0x7b, 0x34, 0x2b, 0x6c, 0x7d, 0x55, 0xd8, 0xad, 0xbd, 0x26, + 0xb6, 0xf6, 0x9d, 0xc1, 0xe1, 0xce, 0x81, 0x6b, 0xe0, 0x3d, 0x39, 0xe9, 0xde, 0xcc, 0x16, 0x96, + 0x3e, 0x5f, 0x58, 0xfa, 0xc7, 0xc2, 0xd2, 0x9f, 0x97, 0x96, 0x36, 0x5f, 0x5a, 0xda, 0xdb, 0xd2, + 0xd2, 0xee, 0x2e, 0xb6, 0xdc, 0x6f, 0xb2, 0x25, 0x9b, 0x6c, 0xc9, 0x23, 0xd9, 0x49, 0xac, 0xfc, + 0x21, 0xbf, 0x5a, 0xbe, 0xf1, 0xf9, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0x52, 0xae, 0x0d, 0xaa, + 0x33, 0x02, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DenomCreationGasConsume != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.DenomCreationGasConsume)) + i-- + dAtA[i] = 0x10 + } + if len(m.DenomCreationFee) > 0 { + for iNdEx := len(m.DenomCreationFee) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DenomCreationFee[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.DenomCreationFee) > 0 { + for _, e := range m.DenomCreationFee { + l = e.Size() + n += 1 + l + sovParams(uint64(l)) + } + } + if m.DenomCreationGasConsume != 0 { + n += 1 + sovParams(uint64(m.DenomCreationGasConsume)) + } + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomCreationFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DenomCreationFee = append(m.DenomCreationFee, types.Coin{}) + if err := m.DenomCreationFee[len(m.DenomCreationFee)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomCreationGasConsume", wireType) + } + m.DenomCreationGasConsume = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DenomCreationGasConsume |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tokenfactory/types/query.pb.go b/x/tokenfactory/types/query.pb.go new file mode 100644 index 000000000..336580fd6 --- /dev/null +++ b/x/tokenfactory/types/query.pb.go @@ -0,0 +1,1331 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tokenfactory/v1beta1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is the request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a4305904e8304e37, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params defines the parameters of the module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a4305904e8304e37, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// QueryDenomAuthorityMetadataRequest defines the request structure for the +// DenomAuthorityMetadata gRPC query. +type QueryDenomAuthorityMetadataRequest struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` +} + +func (m *QueryDenomAuthorityMetadataRequest) Reset() { *m = QueryDenomAuthorityMetadataRequest{} } +func (m *QueryDenomAuthorityMetadataRequest) String() string { return proto.CompactTextString(m) } +func (*QueryDenomAuthorityMetadataRequest) ProtoMessage() {} +func (*QueryDenomAuthorityMetadataRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a4305904e8304e37, []int{2} +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomAuthorityMetadataRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomAuthorityMetadataRequest.Merge(m, src) +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomAuthorityMetadataRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomAuthorityMetadataRequest proto.InternalMessageInfo + +func (m *QueryDenomAuthorityMetadataRequest) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +// QueryDenomAuthorityMetadataResponse defines the response structure for the +// DenomAuthorityMetadata gRPC query. +type QueryDenomAuthorityMetadataResponse struct { + AuthorityMetadata DenomAuthorityMetadata `protobuf:"bytes,1,opt,name=authority_metadata,json=authorityMetadata,proto3" json:"authority_metadata" yaml:"authority_metadata"` +} + +func (m *QueryDenomAuthorityMetadataResponse) Reset() { *m = QueryDenomAuthorityMetadataResponse{} } +func (m *QueryDenomAuthorityMetadataResponse) String() string { return proto.CompactTextString(m) } +func (*QueryDenomAuthorityMetadataResponse) ProtoMessage() {} +func (*QueryDenomAuthorityMetadataResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a4305904e8304e37, []int{3} +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomAuthorityMetadataResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomAuthorityMetadataResponse.Merge(m, src) +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomAuthorityMetadataResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomAuthorityMetadataResponse proto.InternalMessageInfo + +func (m *QueryDenomAuthorityMetadataResponse) GetAuthorityMetadata() DenomAuthorityMetadata { + if m != nil { + return m.AuthorityMetadata + } + return DenomAuthorityMetadata{} +} + +// QueryDenomsFromCreatorRequest defines the request structure for the +// DenomsFromCreator gRPC query. +type QueryDenomsFromCreatorRequest struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty" yaml:"creator"` +} + +func (m *QueryDenomsFromCreatorRequest) Reset() { *m = QueryDenomsFromCreatorRequest{} } +func (m *QueryDenomsFromCreatorRequest) String() string { return proto.CompactTextString(m) } +func (*QueryDenomsFromCreatorRequest) ProtoMessage() {} +func (*QueryDenomsFromCreatorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a4305904e8304e37, []int{4} +} +func (m *QueryDenomsFromCreatorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomsFromCreatorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomsFromCreatorRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDenomsFromCreatorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomsFromCreatorRequest.Merge(m, src) +} +func (m *QueryDenomsFromCreatorRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomsFromCreatorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomsFromCreatorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomsFromCreatorRequest proto.InternalMessageInfo + +func (m *QueryDenomsFromCreatorRequest) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +// QueryDenomsFromCreatorRequest defines the response structure for the +// DenomsFromCreator gRPC query. +type QueryDenomsFromCreatorResponse struct { + Denoms []string `protobuf:"bytes,1,rep,name=denoms,proto3" json:"denoms,omitempty" yaml:"denoms"` +} + +func (m *QueryDenomsFromCreatorResponse) Reset() { *m = QueryDenomsFromCreatorResponse{} } +func (m *QueryDenomsFromCreatorResponse) String() string { return proto.CompactTextString(m) } +func (*QueryDenomsFromCreatorResponse) ProtoMessage() {} +func (*QueryDenomsFromCreatorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a4305904e8304e37, []int{5} +} +func (m *QueryDenomsFromCreatorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomsFromCreatorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomsFromCreatorResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDenomsFromCreatorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomsFromCreatorResponse.Merge(m, src) +} +func (m *QueryDenomsFromCreatorResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomsFromCreatorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomsFromCreatorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomsFromCreatorResponse proto.InternalMessageInfo + +func (m *QueryDenomsFromCreatorResponse) GetDenoms() []string { + if m != nil { + return m.Denoms + } + return nil +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.QueryParamsResponse") + proto.RegisterType((*QueryDenomAuthorityMetadataRequest)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.QueryDenomAuthorityMetadataRequest") + proto.RegisterType((*QueryDenomAuthorityMetadataResponse)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.QueryDenomAuthorityMetadataResponse") + proto.RegisterType((*QueryDenomsFromCreatorRequest)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.QueryDenomsFromCreatorRequest") + proto.RegisterType((*QueryDenomsFromCreatorResponse)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.QueryDenomsFromCreatorResponse") +} + +func init() { proto.RegisterFile("tokenfactory/v1beta1/query.proto", fileDescriptor_a4305904e8304e37) } + +var fileDescriptor_a4305904e8304e37 = []byte{ + // 580 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4f, 0x6b, 0x13, 0x4f, + 0x18, 0xce, 0xf6, 0xf7, 0x4b, 0xa4, 0xe3, 0x1f, 0xcc, 0x58, 0x44, 0x83, 0x6e, 0xda, 0x11, 0xa4, + 0x96, 0xb2, 0x43, 0xa3, 0x5e, 0x7a, 0x50, 0x5c, 0x45, 0xa8, 0x35, 0xa6, 0x5d, 0xf0, 0xe2, 0x25, + 0x4c, 0x92, 0xe9, 0x36, 0x98, 0xdd, 0x77, 0x33, 0x33, 0x11, 0x43, 0xe9, 0xc5, 0x4f, 0x50, 0xd0, + 0x8f, 0xe3, 0x55, 0xe8, 0xb1, 0xe0, 0xc5, 0x53, 0x90, 0xc4, 0x4f, 0x90, 0xbb, 0x20, 0x99, 0x99, + 0xb6, 0xa9, 0x89, 0xa5, 0x5b, 0x7a, 0xca, 0xf0, 0xfe, 0x79, 0x9e, 0xf7, 0x79, 0xde, 0x37, 0x8b, + 0xe6, 0x15, 0xbc, 0xe7, 0xf1, 0x16, 0xab, 0x2b, 0x10, 0x5d, 0xfa, 0x61, 0xa5, 0xc6, 0x15, 0x5b, + 0xa1, 0xed, 0x0e, 0x17, 0x5d, 0x2f, 0x11, 0xa0, 0x00, 0x2f, 0xb5, 0x3b, 0x4c, 0x32, 0xd1, 0x62, + 0x35, 0xe9, 0x99, 0x67, 0x0c, 0x0d, 0xee, 0x8d, 0xf7, 0x79, 0xb6, 0xaf, 0x30, 0x17, 0x42, 0x08, + 0xba, 0x8d, 0x8e, 0x5e, 0x06, 0xa1, 0x70, 0x27, 0x04, 0x08, 0x5b, 0x9c, 0xb2, 0xa4, 0x49, 0x59, + 0x1c, 0x83, 0x62, 0xaa, 0x09, 0xb1, 0xb4, 0xd9, 0xa5, 0x3a, 0xc8, 0x08, 0x24, 0xad, 0x31, 0xc9, + 0x0d, 0xf1, 0xd1, 0x18, 0x09, 0x0b, 0x9b, 0xb1, 0x2e, 0xb6, 0xb5, 0xcb, 0x53, 0xa7, 0x65, 0x1d, + 0xb5, 0x0d, 0xa2, 0xa9, 0xba, 0x65, 0xae, 0x58, 0x83, 0x29, 0x66, 0xab, 0x17, 0xa6, 0x56, 0x27, + 0x4c, 0xb0, 0xc8, 0x92, 0x93, 0x39, 0x84, 0x37, 0x47, 0x94, 0x1b, 0x3a, 0x18, 0xf0, 0x76, 0x87, + 0x4b, 0x45, 0x42, 0x74, 0xe3, 0x44, 0x54, 0x26, 0x10, 0x4b, 0x8e, 0x37, 0x50, 0xce, 0x34, 0xdf, + 0x72, 0xe6, 0x9d, 0xc5, 0xcb, 0xa5, 0x92, 0x77, 0x76, 0x6b, 0x3c, 0x83, 0xe5, 0xff, 0xbf, 0xdf, + 0x2b, 0x66, 0x02, 0x8b, 0x43, 0x5e, 0x23, 0xa2, 0x89, 0x5e, 0xf0, 0x18, 0xa2, 0x67, 0x7f, 0xcb, + 0xb0, 0xe3, 0xe0, 0xfb, 0x28, 0xdb, 0x18, 0x15, 0x68, 0xda, 0x59, 0xff, 0xfa, 0xb0, 0x57, 0xbc, + 0xd2, 0x65, 0x51, 0x6b, 0x95, 0xe8, 0x30, 0x09, 0x4c, 0x9a, 0x7c, 0x75, 0xd0, 0xbd, 0x53, 0xe1, + 0xac, 0x8e, 0x2f, 0x0e, 0xc2, 0x47, 0x9e, 0x55, 0x23, 0x9b, 0xb6, 0xa2, 0xfc, 0x34, 0xa2, 0xa6, + 0x13, 0xf9, 0x0b, 0x23, 0x91, 0xc3, 0x5e, 0xf1, 0xb6, 0x99, 0x72, 0x92, 0x8b, 0x04, 0xf9, 0x89, + 0xa5, 0x91, 0x32, 0xba, 0x7b, 0x3c, 0xbd, 0x7c, 0x29, 0x20, 0x7a, 0x2e, 0x38, 0x53, 0x20, 0x0e, + 0x7d, 0x58, 0x46, 0x97, 0xea, 0x26, 0x62, 0x9d, 0xc0, 0xc3, 0x5e, 0xf1, 0x9a, 0xe1, 0xb0, 0x09, + 0x12, 0x1c, 0x96, 0x90, 0x75, 0xe4, 0xfe, 0x0b, 0xce, 0xfa, 0xf0, 0x00, 0xe5, 0xb4, 0x71, 0xa3, + 0x7d, 0xfe, 0xb7, 0x38, 0xeb, 0xe7, 0x87, 0xbd, 0xe2, 0xd5, 0x31, 0x63, 0x25, 0x09, 0x6c, 0x41, + 0xa9, 0x9f, 0x45, 0x59, 0x8d, 0x86, 0xbf, 0x39, 0x28, 0x67, 0x76, 0x89, 0x9f, 0xa4, 0xb1, 0x6a, + 0xf2, 0xcc, 0x0a, 0x4f, 0xcf, 0xdd, 0x6f, 0x04, 0x90, 0xd5, 0x4f, 0xdf, 0x7f, 0x7d, 0x9e, 0x79, + 0x84, 0x4b, 0xf4, 0xec, 0x40, 0xf6, 0xfe, 0xf1, 0xde, 0x0c, 0xba, 0x39, 0x7d, 0x7d, 0xf8, 0x4d, + 0xea, 0xb9, 0x4e, 0xbd, 0xdf, 0x42, 0xe5, 0xc2, 0xf0, 0xac, 0xee, 0xb7, 0x5a, 0x77, 0x05, 0x97, + 0xd3, 0xe8, 0x36, 0x9b, 0xa4, 0x3b, 0xfa, 0x77, 0x97, 0x4e, 0x1e, 0x25, 0xfe, 0xed, 0xa0, 0xfc, + 0xc4, 0xb5, 0xe0, 0xb5, 0xf3, 0x4d, 0x3f, 0xe5, 0x80, 0x0b, 0xaf, 0x2e, 0x02, 0xca, 0x7a, 0xb0, + 0xa9, 0x3d, 0x58, 0xc7, 0x6b, 0xe9, 0x3d, 0xa8, 0x6e, 0x09, 0x88, 0xaa, 0xf6, 0x7f, 0x42, 0x77, + 0xec, 0x63, 0xd7, 0xaf, 0xec, 0xf7, 0x5d, 0xe7, 0xa0, 0xef, 0x3a, 0x3f, 0xfb, 0xae, 0xb3, 0x37, + 0x70, 0x33, 0x07, 0x03, 0x37, 0xf3, 0x63, 0xe0, 0x66, 0xde, 0x3d, 0x0e, 0x9b, 0x6a, 0xbb, 0x53, + 0xf3, 0xea, 0x10, 0x8d, 0xd1, 0xd1, 0x63, 0x3a, 0xfa, 0x91, 0x9e, 0xf8, 0xd8, 0xaa, 0x6e, 0xc2, + 0x65, 0x2d, 0xa7, 0x3f, 0xb2, 0x0f, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x97, 0xba, 0xeb, 0xa4, + 0x65, 0x06, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Params defines a gRPC query method that returns the tokenfactory module's + // parameters. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // DenomAuthorityMetadata defines a gRPC query method for fetching + // DenomAuthorityMetadata for a particular denom. + DenomAuthorityMetadata(ctx context.Context, in *QueryDenomAuthorityMetadataRequest, opts ...grpc.CallOption) (*QueryDenomAuthorityMetadataResponse, error) + // DenomsFromCreator defines a gRPC query method for fetching all + // denominations created by a specific admin/creator. + DenomsFromCreator(ctx context.Context, in *QueryDenomsFromCreatorRequest, opts ...grpc.CallOption) (*QueryDenomsFromCreatorResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.tokenfactory.v1beta1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) DenomAuthorityMetadata(ctx context.Context, in *QueryDenomAuthorityMetadataRequest, opts ...grpc.CallOption) (*QueryDenomAuthorityMetadataResponse, error) { + out := new(QueryDenomAuthorityMetadataResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.tokenfactory.v1beta1.Query/DenomAuthorityMetadata", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) DenomsFromCreator(ctx context.Context, in *QueryDenomsFromCreatorRequest, opts ...grpc.CallOption) (*QueryDenomsFromCreatorResponse, error) { + out := new(QueryDenomsFromCreatorResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.tokenfactory.v1beta1.Query/DenomsFromCreator", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Params defines a gRPC query method that returns the tokenfactory module's + // parameters. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // DenomAuthorityMetadata defines a gRPC query method for fetching + // DenomAuthorityMetadata for a particular denom. + DenomAuthorityMetadata(context.Context, *QueryDenomAuthorityMetadataRequest) (*QueryDenomAuthorityMetadataResponse, error) + // DenomsFromCreator defines a gRPC query method for fetching all + // denominations created by a specific admin/creator. + DenomsFromCreator(context.Context, *QueryDenomsFromCreatorRequest) (*QueryDenomsFromCreatorResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (*UnimplementedQueryServer) DenomAuthorityMetadata(ctx context.Context, req *QueryDenomAuthorityMetadataRequest) (*QueryDenomAuthorityMetadataResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DenomAuthorityMetadata not implemented") +} +func (*UnimplementedQueryServer) DenomsFromCreator(ctx context.Context, req *QueryDenomsFromCreatorRequest) (*QueryDenomsFromCreatorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DenomsFromCreator not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.tokenfactory.v1beta1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_DenomAuthorityMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryDenomAuthorityMetadataRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DenomAuthorityMetadata(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.tokenfactory.v1beta1.Query/DenomAuthorityMetadata", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DenomAuthorityMetadata(ctx, req.(*QueryDenomAuthorityMetadataRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_DenomsFromCreator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryDenomsFromCreatorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DenomsFromCreator(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.tokenfactory.v1beta1.Query/DenomsFromCreator", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DenomsFromCreator(ctx, req.(*QueryDenomsFromCreatorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "quasarlabs.quasarnode.tokenfactory.v1beta1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "DenomAuthorityMetadata", + Handler: _Query_DenomAuthorityMetadata_Handler, + }, + { + MethodName: "DenomsFromCreator", + Handler: _Query_DenomsFromCreator_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "tokenfactory/v1beta1/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryDenomAuthorityMetadataRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDenomAuthorityMetadataRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomAuthorityMetadataRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomAuthorityMetadataResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDenomAuthorityMetadataResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomAuthorityMetadataResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.AuthorityMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryDenomsFromCreatorRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDenomsFromCreatorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomsFromCreatorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomsFromCreatorResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDenomsFromCreatorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomsFromCreatorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denoms) > 0 { + for iNdEx := len(m.Denoms) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Denoms[iNdEx]) + copy(dAtA[i:], m.Denoms[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denoms[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryDenomAuthorityMetadataRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDenomAuthorityMetadataResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.AuthorityMetadata.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryDenomsFromCreatorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDenomsFromCreatorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Denoms) > 0 { + for _, s := range m.Denoms { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomAuthorityMetadataRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDenomAuthorityMetadataRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomAuthorityMetadataRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomAuthorityMetadataResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDenomAuthorityMetadataResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomAuthorityMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AuthorityMetadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.AuthorityMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomsFromCreatorRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDenomsFromCreatorRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomsFromCreatorRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomsFromCreatorResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDenomsFromCreatorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomsFromCreatorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denoms", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denoms = append(m.Denoms, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tokenfactory/types/query.pb.gw.go b/x/tokenfactory/types/query.pb.gw.go new file mode 100644 index 000000000..e58f0a856 --- /dev/null +++ b/x/tokenfactory/types/query.pb.gw.go @@ -0,0 +1,355 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: tokenfactory/v1beta1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_DenomAuthorityMetadata_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomAuthorityMetadataRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := client.DenomAuthorityMetadata(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DenomAuthorityMetadata_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomAuthorityMetadataRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := server.DenomAuthorityMetadata(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_DenomsFromCreator_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomsFromCreatorRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["creator"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "creator") + } + + protoReq.Creator, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "creator", err) + } + + msg, err := client.DenomsFromCreator(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DenomsFromCreator_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomsFromCreatorRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["creator"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "creator") + } + + protoReq.Creator, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "creator", err) + } + + msg, err := server.DenomsFromCreator(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomAuthorityMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DenomAuthorityMetadata_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomAuthorityMetadata_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomsFromCreator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DenomsFromCreator_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomsFromCreator_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomAuthorityMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DenomAuthorityMetadata_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomAuthorityMetadata_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomsFromCreator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DenomsFromCreator_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomsFromCreator_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quasarlabs.quasarnode.tokenfactory.v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_DenomAuthorityMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"quasarlabs.quasarnode.tokenfactory.v1beta1", "denoms", "denom", "authority_metadata"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_DenomsFromCreator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"quasarlabs.quasarnode.tokenfactory.v1beta1", "denoms_from_creator", "creator"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_DenomAuthorityMetadata_0 = runtime.ForwardResponseMessage + + forward_Query_DenomsFromCreator_0 = runtime.ForwardResponseMessage +) diff --git a/x/tokenfactory/types/tx.pb.go b/x/tokenfactory/types/tx.pb.go new file mode 100644 index 000000000..7f69d4df5 --- /dev/null +++ b/x/tokenfactory/types/tx.pb.go @@ -0,0 +1,2342 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tokenfactory/v1beta1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/cosmos-sdk/x/bank/types" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgCreateDenom defines the message structure for the CreateDenom gRPC service +// method. It allows an account to create a new denom. It requires a sender +// address and a sub denomination. The (sender_address, sub_denomination) tuple +// must be unique and cannot be re-used. +// +// The resulting denom created is defined as +// . The resulting denom's admin is +// originally set to be the creator, but this can be changed later. The token +// denom does not indicate the current admin. +type MsgCreateDenom struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + // subdenom can be up to 44 "alphanumeric" characters long. + Subdenom string `protobuf:"bytes,2,opt,name=subdenom,proto3" json:"subdenom,omitempty" yaml:"subdenom"` +} + +func (m *MsgCreateDenom) Reset() { *m = MsgCreateDenom{} } +func (m *MsgCreateDenom) String() string { return proto.CompactTextString(m) } +func (*MsgCreateDenom) ProtoMessage() {} +func (*MsgCreateDenom) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{0} +} +func (m *MsgCreateDenom) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateDenom) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateDenom.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateDenom) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateDenom.Merge(m, src) +} +func (m *MsgCreateDenom) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateDenom) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateDenom.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateDenom proto.InternalMessageInfo + +func (m *MsgCreateDenom) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgCreateDenom) GetSubdenom() string { + if m != nil { + return m.Subdenom + } + return "" +} + +// MsgCreateDenomResponse is the return value of MsgCreateDenom +// It returns the full string of the newly created denom +type MsgCreateDenomResponse struct { + NewTokenDenom string `protobuf:"bytes,1,opt,name=new_token_denom,json=newTokenDenom,proto3" json:"new_token_denom,omitempty" yaml:"new_token_denom"` +} + +func (m *MsgCreateDenomResponse) Reset() { *m = MsgCreateDenomResponse{} } +func (m *MsgCreateDenomResponse) String() string { return proto.CompactTextString(m) } +func (*MsgCreateDenomResponse) ProtoMessage() {} +func (*MsgCreateDenomResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{1} +} +func (m *MsgCreateDenomResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateDenomResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateDenomResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateDenomResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateDenomResponse.Merge(m, src) +} +func (m *MsgCreateDenomResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateDenomResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateDenomResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateDenomResponse proto.InternalMessageInfo + +func (m *MsgCreateDenomResponse) GetNewTokenDenom() string { + if m != nil { + return m.NewTokenDenom + } + return "" +} + +// MsgMint is the sdk.Msg type for allowing an admin account to mint +// more of a token. For now, we only support minting to the sender account +type MsgMint struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount" yaml:"amount"` + MintToAddress string `protobuf:"bytes,3,opt,name=mintToAddress,proto3" json:"mintToAddress,omitempty" yaml:"mint_to_address"` +} + +func (m *MsgMint) Reset() { *m = MsgMint{} } +func (m *MsgMint) String() string { return proto.CompactTextString(m) } +func (*MsgMint) ProtoMessage() {} +func (*MsgMint) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{2} +} +func (m *MsgMint) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMint.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMint) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMint.Merge(m, src) +} +func (m *MsgMint) XXX_Size() int { + return m.Size() +} +func (m *MsgMint) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMint.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMint proto.InternalMessageInfo + +func (m *MsgMint) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgMint) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +func (m *MsgMint) GetMintToAddress() string { + if m != nil { + return m.MintToAddress + } + return "" +} + +type MsgMintResponse struct { +} + +func (m *MsgMintResponse) Reset() { *m = MsgMintResponse{} } +func (m *MsgMintResponse) String() string { return proto.CompactTextString(m) } +func (*MsgMintResponse) ProtoMessage() {} +func (*MsgMintResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{3} +} +func (m *MsgMintResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMintResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMintResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMintResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMintResponse.Merge(m, src) +} +func (m *MsgMintResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgMintResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMintResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMintResponse proto.InternalMessageInfo + +// MsgBurn is the sdk.Msg type for allowing an admin account to burn +// a token. For now, we only support burning from the sender account. +type MsgBurn struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount" yaml:"amount"` + BurnFromAddress string `protobuf:"bytes,3,opt,name=burnFromAddress,proto3" json:"burnFromAddress,omitempty" yaml:"burn_from_address"` +} + +func (m *MsgBurn) Reset() { *m = MsgBurn{} } +func (m *MsgBurn) String() string { return proto.CompactTextString(m) } +func (*MsgBurn) ProtoMessage() {} +func (*MsgBurn) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{4} +} +func (m *MsgBurn) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgBurn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgBurn.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgBurn) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgBurn.Merge(m, src) +} +func (m *MsgBurn) XXX_Size() int { + return m.Size() +} +func (m *MsgBurn) XXX_DiscardUnknown() { + xxx_messageInfo_MsgBurn.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgBurn proto.InternalMessageInfo + +func (m *MsgBurn) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgBurn) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +func (m *MsgBurn) GetBurnFromAddress() string { + if m != nil { + return m.BurnFromAddress + } + return "" +} + +type MsgBurnResponse struct { +} + +func (m *MsgBurnResponse) Reset() { *m = MsgBurnResponse{} } +func (m *MsgBurnResponse) String() string { return proto.CompactTextString(m) } +func (*MsgBurnResponse) ProtoMessage() {} +func (*MsgBurnResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{5} +} +func (m *MsgBurnResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgBurnResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgBurnResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgBurnResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgBurnResponse.Merge(m, src) +} +func (m *MsgBurnResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgBurnResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgBurnResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgBurnResponse proto.InternalMessageInfo + +// MsgChangeAdmin is the sdk.Msg type for allowing an admin account to reassign +// adminship of a denom to a new account +type MsgChangeAdmin struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` + NewAdmin string `protobuf:"bytes,3,opt,name=new_admin,json=newAdmin,proto3" json:"new_admin,omitempty" yaml:"new_admin"` +} + +func (m *MsgChangeAdmin) Reset() { *m = MsgChangeAdmin{} } +func (m *MsgChangeAdmin) String() string { return proto.CompactTextString(m) } +func (*MsgChangeAdmin) ProtoMessage() {} +func (*MsgChangeAdmin) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{6} +} +func (m *MsgChangeAdmin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChangeAdmin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChangeAdmin.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgChangeAdmin) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChangeAdmin.Merge(m, src) +} +func (m *MsgChangeAdmin) XXX_Size() int { + return m.Size() +} +func (m *MsgChangeAdmin) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChangeAdmin.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgChangeAdmin proto.InternalMessageInfo + +func (m *MsgChangeAdmin) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgChangeAdmin) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *MsgChangeAdmin) GetNewAdmin() string { + if m != nil { + return m.NewAdmin + } + return "" +} + +// MsgChangeAdminResponse defines the response structure for an executed +// MsgChangeAdmin message. +type MsgChangeAdminResponse struct { +} + +func (m *MsgChangeAdminResponse) Reset() { *m = MsgChangeAdminResponse{} } +func (m *MsgChangeAdminResponse) String() string { return proto.CompactTextString(m) } +func (*MsgChangeAdminResponse) ProtoMessage() {} +func (*MsgChangeAdminResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{7} +} +func (m *MsgChangeAdminResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChangeAdminResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChangeAdminResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgChangeAdminResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChangeAdminResponse.Merge(m, src) +} +func (m *MsgChangeAdminResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgChangeAdminResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChangeAdminResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgChangeAdminResponse proto.InternalMessageInfo + +// MsgSetDenomMetadata is the sdk.Msg type for allowing an admin account to set +// the denom's bank metadata +type MsgSetDenomMetadata struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Metadata types1.Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata" yaml:"metadata"` +} + +func (m *MsgSetDenomMetadata) Reset() { *m = MsgSetDenomMetadata{} } +func (m *MsgSetDenomMetadata) String() string { return proto.CompactTextString(m) } +func (*MsgSetDenomMetadata) ProtoMessage() {} +func (*MsgSetDenomMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{8} +} +func (m *MsgSetDenomMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetDenomMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetDenomMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetDenomMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetDenomMetadata.Merge(m, src) +} +func (m *MsgSetDenomMetadata) XXX_Size() int { + return m.Size() +} +func (m *MsgSetDenomMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetDenomMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetDenomMetadata proto.InternalMessageInfo + +func (m *MsgSetDenomMetadata) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgSetDenomMetadata) GetMetadata() types1.Metadata { + if m != nil { + return m.Metadata + } + return types1.Metadata{} +} + +// MsgSetDenomMetadataResponse defines the response structure for an executed +// MsgSetDenomMetadata message. +type MsgSetDenomMetadataResponse struct { +} + +func (m *MsgSetDenomMetadataResponse) Reset() { *m = MsgSetDenomMetadataResponse{} } +func (m *MsgSetDenomMetadataResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSetDenomMetadataResponse) ProtoMessage() {} +func (*MsgSetDenomMetadataResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae6d2a5cb7a1208, []int{9} +} +func (m *MsgSetDenomMetadataResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetDenomMetadataResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetDenomMetadataResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetDenomMetadataResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetDenomMetadataResponse.Merge(m, src) +} +func (m *MsgSetDenomMetadataResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSetDenomMetadataResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetDenomMetadataResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetDenomMetadataResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgCreateDenom)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgCreateDenom") + proto.RegisterType((*MsgCreateDenomResponse)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgCreateDenomResponse") + proto.RegisterType((*MsgMint)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgMint") + proto.RegisterType((*MsgMintResponse)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgMintResponse") + proto.RegisterType((*MsgBurn)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgBurn") + proto.RegisterType((*MsgBurnResponse)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgBurnResponse") + proto.RegisterType((*MsgChangeAdmin)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgChangeAdmin") + proto.RegisterType((*MsgChangeAdminResponse)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgChangeAdminResponse") + proto.RegisterType((*MsgSetDenomMetadata)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgSetDenomMetadata") + proto.RegisterType((*MsgSetDenomMetadataResponse)(nil), "quasarlabs.quasarnode.tokenfactory.v1beta1.MsgSetDenomMetadataResponse") +} + +func init() { proto.RegisterFile("tokenfactory/v1beta1/tx.proto", fileDescriptor_5ae6d2a5cb7a1208) } + +var fileDescriptor_5ae6d2a5cb7a1208 = []byte{ + // 658 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0xcf, 0x4e, 0xd5, 0x4e, + 0x14, 0xbe, 0xfd, 0xf1, 0x03, 0x61, 0x10, 0x2f, 0x14, 0xc4, 0xeb, 0x55, 0x5a, 0x33, 0x0b, 0xa3, + 0x2e, 0xda, 0x00, 0x71, 0x83, 0x0b, 0xa5, 0x18, 0x74, 0xd3, 0x98, 0x54, 0x56, 0xc6, 0xe4, 0x66, + 0x7a, 0x3b, 0x94, 0x06, 0x3a, 0x83, 0x9d, 0xa9, 0xc0, 0x43, 0x98, 0xb8, 0x30, 0xae, 0x7c, 0x10, + 0x97, 0xae, 0x0c, 0x4b, 0x96, 0xae, 0x1a, 0x03, 0x6f, 0xd0, 0x27, 0x30, 0xd3, 0x99, 0xfe, 0xb9, + 0x17, 0x17, 0x16, 0x17, 0xee, 0x7a, 0x7b, 0xce, 0xf7, 0x9d, 0xf3, 0x9d, 0xf3, 0x9d, 0x5b, 0xb0, + 0xc2, 0xe9, 0x3e, 0x26, 0xbb, 0x68, 0xc8, 0x69, 0x72, 0x62, 0xbf, 0x5f, 0xf5, 0x31, 0x47, 0xab, + 0x36, 0x3f, 0xb6, 0x0e, 0x13, 0xca, 0xa9, 0xfe, 0xe8, 0x5d, 0x8a, 0x18, 0x4a, 0x0e, 0x90, 0xcf, + 0x2c, 0xf9, 0x48, 0x68, 0x80, 0xad, 0x26, 0xc8, 0x52, 0xa0, 0xfe, 0x52, 0x48, 0x43, 0x5a, 0xc0, + 0x6c, 0xf1, 0x24, 0x19, 0xfa, 0xc6, 0x90, 0xb2, 0x98, 0x32, 0xdb, 0x47, 0x0c, 0x57, 0xfc, 0x43, + 0x1a, 0x91, 0x4b, 0x71, 0xb2, 0x5f, 0xc5, 0xc5, 0x0f, 0x19, 0x87, 0x07, 0xe0, 0x86, 0xcb, 0xc2, + 0xad, 0x04, 0x23, 0x8e, 0x9f, 0x63, 0x42, 0x63, 0xfd, 0x21, 0x98, 0x62, 0x98, 0x04, 0x38, 0xe9, + 0x69, 0xf7, 0xb4, 0x07, 0x33, 0xce, 0x42, 0x9e, 0x99, 0x73, 0x27, 0x28, 0x3e, 0xd8, 0x80, 0xf2, + 0x3d, 0xf4, 0x54, 0x82, 0x6e, 0x83, 0x69, 0x96, 0xfa, 0x81, 0x80, 0xf5, 0xfe, 0x2b, 0x92, 0x17, + 0xf3, 0xcc, 0xec, 0xaa, 0x64, 0x15, 0x81, 0x5e, 0x95, 0x04, 0xdf, 0x82, 0xe5, 0xd1, 0x6a, 0x1e, + 0x66, 0x87, 0x94, 0x30, 0xac, 0x3b, 0xa0, 0x4b, 0xf0, 0xd1, 0xa0, 0x50, 0x3e, 0x90, 0x8c, 0xb2, + 0x7c, 0x3f, 0xcf, 0xcc, 0x65, 0xc9, 0x38, 0x96, 0x00, 0xbd, 0x39, 0x82, 0x8f, 0x76, 0xc4, 0x8b, + 0x82, 0x0b, 0x7e, 0xd3, 0xc0, 0x35, 0x97, 0x85, 0x6e, 0x44, 0x78, 0x1b, 0x15, 0x2f, 0xc1, 0x14, + 0x8a, 0x69, 0x4a, 0x78, 0xa1, 0x61, 0x76, 0xed, 0xb6, 0x25, 0x67, 0x66, 0x89, 0x99, 0x96, 0xe3, + 0xb7, 0xb6, 0x68, 0x44, 0x9c, 0x9b, 0xa7, 0x99, 0xd9, 0xa9, 0x99, 0x24, 0x0c, 0x7a, 0x0a, 0xaf, + 0x3f, 0x03, 0x73, 0x71, 0x44, 0xf8, 0x0e, 0xdd, 0x0c, 0x82, 0x04, 0x33, 0xd6, 0x9b, 0x18, 0x97, + 0x20, 0xc2, 0x03, 0x4e, 0x07, 0x48, 0x26, 0x40, 0x6f, 0x14, 0x00, 0x17, 0x40, 0x57, 0x29, 0x28, + 0x27, 0x03, 0xbf, 0x4b, 0x55, 0x4e, 0x9a, 0x90, 0x7f, 0xa3, 0x6a, 0x1b, 0x74, 0xfd, 0x34, 0x21, + 0xdb, 0x09, 0x8d, 0x47, 0x75, 0xdd, 0xcd, 0x33, 0xb3, 0x27, 0x31, 0x22, 0x61, 0xb0, 0x9b, 0xd0, + 0xb8, 0x56, 0x36, 0x0e, 0x52, 0xda, 0x84, 0x8e, 0x4a, 0xdb, 0x67, 0x4d, 0xda, 0x6f, 0x0f, 0x91, + 0x10, 0x6f, 0x06, 0x71, 0xd4, 0x4a, 0xe2, 0x7d, 0x30, 0xd9, 0xf4, 0xde, 0x7c, 0x9e, 0x99, 0xd7, + 0x65, 0xa6, 0xf2, 0x87, 0x0c, 0xeb, 0xab, 0x60, 0x46, 0x58, 0x07, 0x09, 0x7e, 0xd5, 0xfa, 0x52, + 0x9e, 0x99, 0xf3, 0xb5, 0xab, 0x8a, 0x10, 0xf4, 0xa6, 0x09, 0x3e, 0x2a, 0xba, 0x80, 0x3d, 0x69, + 0xd4, 0xba, 0xaf, 0xaa, 0xe5, 0x4f, 0x1a, 0x58, 0x74, 0x59, 0xf8, 0x1a, 0xf3, 0xc2, 0x74, 0x2e, + 0xe6, 0x28, 0x40, 0x1c, 0xb5, 0xe9, 0xdb, 0x03, 0xd3, 0xb1, 0x82, 0xa9, 0xe5, 0xac, 0xd4, 0xcb, + 0x21, 0xfb, 0xd5, 0x72, 0x4a, 0x6e, 0xe7, 0x96, 0x5a, 0x90, 0xba, 0xac, 0x12, 0x0c, 0xbd, 0x8a, + 0x07, 0xae, 0x80, 0x3b, 0xbf, 0xe9, 0xaa, 0xec, 0x7a, 0xed, 0xeb, 0x24, 0x98, 0x70, 0x59, 0xa8, + 0x7f, 0xd0, 0xc0, 0x6c, 0xf3, 0xd8, 0x37, 0xac, 0x3f, 0xff, 0x07, 0xb2, 0x46, 0x4f, 0xb7, 0xef, + 0x5c, 0x1d, 0x5b, 0x9d, 0xfd, 0x31, 0xf8, 0xbf, 0x38, 0xd7, 0xf5, 0x96, 0x5c, 0x02, 0xd4, 0x7f, + 0x72, 0x05, 0x50, 0xb3, 0x72, 0x71, 0x52, 0x6d, 0x2b, 0x0b, 0x50, 0xeb, 0xca, 0x4d, 0xd3, 0xcb, + 0x1d, 0x34, 0x1c, 0xdf, 0x7a, 0x07, 0x35, 0xb6, 0xfd, 0x0e, 0x2e, 0x3b, 0x5a, 0xff, 0xa2, 0x81, + 0xf9, 0x4b, 0x76, 0x7e, 0xda, 0x92, 0x78, 0x9c, 0xa0, 0xff, 0xe2, 0x2f, 0x09, 0xca, 0xf6, 0x9c, + 0x57, 0xa7, 0xe7, 0x86, 0x76, 0x76, 0x6e, 0x68, 0x3f, 0xcf, 0x0d, 0xed, 0xe3, 0x85, 0xd1, 0x39, + 0xbb, 0x30, 0x3a, 0x3f, 0x2e, 0x8c, 0xce, 0x9b, 0xc7, 0x61, 0xc4, 0xf7, 0x52, 0xdf, 0x1a, 0xd2, + 0xd8, 0xae, 0x8b, 0xd9, 0x75, 0x31, 0xfb, 0xd8, 0x1e, 0xf9, 0xfe, 0xf2, 0x93, 0x43, 0xcc, 0xfc, + 0xa9, 0xe2, 0xcb, 0xb7, 0xfe, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x19, 0x80, 0xbb, 0x0e, 0x9c, 0x07, + 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + CreateDenom(ctx context.Context, in *MsgCreateDenom, opts ...grpc.CallOption) (*MsgCreateDenomResponse, error) + Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) + Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) + ChangeAdmin(ctx context.Context, in *MsgChangeAdmin, opts ...grpc.CallOption) (*MsgChangeAdminResponse, error) + SetDenomMetadata(ctx context.Context, in *MsgSetDenomMetadata, opts ...grpc.CallOption) (*MsgSetDenomMetadataResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) CreateDenom(ctx context.Context, in *MsgCreateDenom, opts ...grpc.CallOption) (*MsgCreateDenomResponse, error) { + out := new(MsgCreateDenomResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/CreateDenom", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) { + out := new(MsgMintResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/Mint", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) { + out := new(MsgBurnResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/Burn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ChangeAdmin(ctx context.Context, in *MsgChangeAdmin, opts ...grpc.CallOption) (*MsgChangeAdminResponse, error) { + out := new(MsgChangeAdminResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/ChangeAdmin", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) SetDenomMetadata(ctx context.Context, in *MsgSetDenomMetadata, opts ...grpc.CallOption) (*MsgSetDenomMetadataResponse, error) { + out := new(MsgSetDenomMetadataResponse) + err := c.cc.Invoke(ctx, "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/SetDenomMetadata", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + CreateDenom(context.Context, *MsgCreateDenom) (*MsgCreateDenomResponse, error) + Mint(context.Context, *MsgMint) (*MsgMintResponse, error) + Burn(context.Context, *MsgBurn) (*MsgBurnResponse, error) + ChangeAdmin(context.Context, *MsgChangeAdmin) (*MsgChangeAdminResponse, error) + SetDenomMetadata(context.Context, *MsgSetDenomMetadata) (*MsgSetDenomMetadataResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) CreateDenom(ctx context.Context, req *MsgCreateDenom) (*MsgCreateDenomResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateDenom not implemented") +} +func (*UnimplementedMsgServer) Mint(ctx context.Context, req *MsgMint) (*MsgMintResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Mint not implemented") +} +func (*UnimplementedMsgServer) Burn(ctx context.Context, req *MsgBurn) (*MsgBurnResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Burn not implemented") +} +func (*UnimplementedMsgServer) ChangeAdmin(ctx context.Context, req *MsgChangeAdmin) (*MsgChangeAdminResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChangeAdmin not implemented") +} +func (*UnimplementedMsgServer) SetDenomMetadata(ctx context.Context, req *MsgSetDenomMetadata) (*MsgSetDenomMetadataResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetDenomMetadata not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_CreateDenom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgCreateDenom) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).CreateDenom(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/CreateDenom", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).CreateDenom(ctx, req.(*MsgCreateDenom)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Mint_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgMint) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Mint(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/Mint", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Mint(ctx, req.(*MsgMint)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Burn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgBurn) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Burn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/Burn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Burn(ctx, req.(*MsgBurn)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ChangeAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChangeAdmin) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ChangeAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/ChangeAdmin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChangeAdmin(ctx, req.(*MsgChangeAdmin)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_SetDenomMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSetDenomMetadata) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SetDenomMetadata(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quasarlabs.quasarnode.tokenfactory.v1beta1.Msg/SetDenomMetadata", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SetDenomMetadata(ctx, req.(*MsgSetDenomMetadata)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "quasarlabs.quasarnode.tokenfactory.v1beta1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateDenom", + Handler: _Msg_CreateDenom_Handler, + }, + { + MethodName: "Mint", + Handler: _Msg_Mint_Handler, + }, + { + MethodName: "Burn", + Handler: _Msg_Burn_Handler, + }, + { + MethodName: "ChangeAdmin", + Handler: _Msg_ChangeAdmin_Handler, + }, + { + MethodName: "SetDenomMetadata", + Handler: _Msg_SetDenomMetadata_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "tokenfactory/v1beta1/tx.proto", +} + +func (m *MsgCreateDenom) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgCreateDenom) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateDenom) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Subdenom) > 0 { + i -= len(m.Subdenom) + copy(dAtA[i:], m.Subdenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.Subdenom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgCreateDenomResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgCreateDenomResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateDenomResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.NewTokenDenom) > 0 { + i -= len(m.NewTokenDenom) + copy(dAtA[i:], m.NewTokenDenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.NewTokenDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMint) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMint) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMint) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.MintToAddress) > 0 { + i -= len(m.MintToAddress) + copy(dAtA[i:], m.MintToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.MintToAddress))) + i-- + dAtA[i] = 0x1a + } + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMintResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMintResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMintResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgBurn) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgBurn) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgBurn) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.BurnFromAddress) > 0 { + i -= len(m.BurnFromAddress) + copy(dAtA[i:], m.BurnFromAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.BurnFromAddress))) + i-- + dAtA[i] = 0x1a + } + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgBurnResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgBurnResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgBurnResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgChangeAdmin) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgChangeAdmin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChangeAdmin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.NewAdmin) > 0 { + i -= len(m.NewAdmin) + copy(dAtA[i:], m.NewAdmin) + i = encodeVarintTx(dAtA, i, uint64(len(m.NewAdmin))) + i-- + dAtA[i] = 0x1a + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTx(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChangeAdminResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgChangeAdminResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChangeAdminResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgSetDenomMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetDenomMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetDenomMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSetDenomMetadataResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetDenomMetadataResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetDenomMetadataResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgCreateDenom) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Subdenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgCreateDenomResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.NewTokenDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgMint) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.MintToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgMintResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgBurn) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.BurnFromAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgBurnResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgChangeAdmin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.NewAdmin) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChangeAdminResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgSetDenomMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Metadata.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgSetDenomMetadataResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgCreateDenom) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgCreateDenom: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreateDenom: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Subdenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Subdenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgCreateDenomResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgCreateDenomResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreateDenomResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewTokenDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewTokenDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgMint) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgMint: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMint: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MintToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MintToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgMintResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgMintResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMintResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgBurn) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgBurn: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgBurn: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BurnFromAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BurnFromAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgBurnResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgBurnResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgBurnResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgChangeAdmin) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgChangeAdmin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChangeAdmin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewAdmin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewAdmin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgChangeAdminResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgChangeAdminResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChangeAdminResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSetDenomMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetDenomMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetDenomMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSetDenomMetadataResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetDenomMetadataResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetDenomMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) From 3834660ff8d249926cd3417e101a6a4ab9358c9d Mon Sep 17 00:00:00 2001 From: akure Date: Tue, 8 Aug 2023 16:10:50 +0530 Subject: [PATCH 2/7] fix open api docs --- docs/package-lock.json | 1324 ++++ docs/package.json | 10 +- docs/static/openapi.yml | 9870 ++++++++---------------------- docs/swagger-combine.config.json | 20 +- docs/yarn.lock | 261 +- scripts/generate-docs.sh | 26 +- 6 files changed, 3967 insertions(+), 7544 deletions(-) create mode 100644 docs/package-lock.json diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 000000000..410458b91 --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,1324 @@ +{ + "name": "docs", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "docs", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "swagger-combine": "^1.4.0", + "swagger2openapi": "^7.0.3" + } + }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^9.0.6", + "@apidevtools/openapi-schemas": "^2.0.4", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "z-schema": "^5.0.1" + }, + "peerDependencies": { + "openapi-types": ">=7" + } + }, + "node_modules/@exodus/schemasafe": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.0.0-rc.7.tgz", + "integrity": "sha512-+1mBLsa+vvlV0lwEAP1hwgmOPkjMnoJ8hyCMfCCJga0sVDwDzrPJjnxZwdDaUmOh/vbFHQGBTk+FxsVjoI/CjQ==" + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==" + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==" + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/http2-client": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", + "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q==", + "deprecated": "Please switch to @apidevtools/json-schema-ref-parser", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "9.0.9" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-h2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", + "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", + "dependencies": { + "http2-client": "^1.2.5" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-readfiles": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", + "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", + "dependencies": { + "es6-promise": "^3.2.1" + } + }, + "node_modules/oas-kit-common": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", + "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", + "dependencies": { + "fast-safe-stringify": "^2.0.7" + } + }, + "node_modules/oas-linter": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", + "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", + "dependencies": { + "@exodus/schemasafe": "^1.0.0-rc.2", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-resolver": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", + "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", + "dependencies": { + "node-fetch-h2": "^2.3.0", + "oas-kit-common": "^1.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "resolve": "resolve.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-schema-walker": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", + "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-validator": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz", + "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", + "dependencies": { + "call-me-maybe": "^1.0.1", + "oas-kit-common": "^1.0.8", + "oas-linter": "^3.2.2", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "reftools": "^1.1.9", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "peer": true + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/reftools": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", + "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dependencies": { + "should-type": "^1.4.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==" + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/swagger-combine": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/swagger-combine/-/swagger-combine-1.4.0.tgz", + "integrity": "sha512-nVQPzSGixSJ6U3BSTBYswIbamumNCz1ZXPqnCrXYz6BHlSeOtfGKuyZ+sAWtpOepUFuOu93x+VOIzAxLKK6xYw==", + "dependencies": { + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0", + "json-schema-ref-parser": "^9.0.9", + "lodash": "^4.17.21", + "minimist": "^1.2.5", + "swagger-parser": "^10.0.3", + "traverse": "^0.6.6", + "url-join": "^4.0.1" + }, + "bin": { + "swagger-combine": "bin/swagger-combine" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", + "dependencies": { + "@apidevtools/swagger-parser": "10.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swagger2openapi": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.3.tgz", + "integrity": "sha512-JSFUmXSR7Qx9WwSKCEqaL4oQfhLLCU2r8Zgf30g15FdSkihItZ6fKFnqSsfqQ6MsmnLlcBf8+OhnQHbi1R0ydg==", + "dependencies": { + "call-me-maybe": "^1.0.1", + "node-fetch": "^2.6.1", + "node-fetch-h2": "^2.3.0", + "node-readfiles": "^0.2.0", + "oas-kit-common": "^1.0.8", + "oas-resolver": "^2.5.2", + "oas-schema-walker": "^1.1.5", + "oas-validator": "^5.0.3", + "reftools": "^1.1.6", + "yaml": "^1.10.0", + "yargs": "^15.3.1" + }, + "bin": { + "boast": "boast.js", + "oas-validate": "oas-validate.js", + "swagger2openapi": "swagger2openapi.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/swagger2openapi/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/swagger2openapi/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/swagger2openapi/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/swagger2openapi/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/swagger2openapi/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==" + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" + }, + "node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/z-schema": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.4.tgz", + "integrity": "sha512-gm/lx3hDzJNcLwseIeQVm1UcwhWIKpSB4NqH89pTBtFns4k/HDHudsICtvG05Bvw/Mv3jMyk700y5dadueLHdA==", + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "commander": "^2.20.3" + } + } + }, + "dependencies": { + "@apidevtools/json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", + "requires": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, + "@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==" + }, + "@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" + }, + "@apidevtools/swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", + "requires": { + "@apidevtools/json-schema-ref-parser": "^9.0.6", + "@apidevtools/openapi-schemas": "^2.0.4", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "z-schema": "^5.0.1" + } + }, + "@exodus/schemasafe": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.0.0-rc.7.tgz", + "integrity": "sha512-+1mBLsa+vvlV0lwEAP1hwgmOPkjMnoJ8hyCMfCCJga0sVDwDzrPJjnxZwdDaUmOh/vbFHQGBTk+FxsVjoI/CjQ==" + }, + "@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "http2-client": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", + "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q==", + "requires": { + "@apidevtools/json-schema-ref-parser": "9.0.9" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-fetch-h2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", + "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", + "requires": { + "http2-client": "^1.2.5" + } + }, + "node-readfiles": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", + "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", + "requires": { + "es6-promise": "^3.2.1" + } + }, + "oas-kit-common": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", + "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", + "requires": { + "fast-safe-stringify": "^2.0.7" + } + }, + "oas-linter": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", + "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", + "requires": { + "@exodus/schemasafe": "^1.0.0-rc.2", + "should": "^13.2.1", + "yaml": "^1.10.0" + } + }, + "oas-resolver": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", + "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", + "requires": { + "node-fetch-h2": "^2.3.0", + "oas-kit-common": "^1.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + } + }, + "oas-schema-walker": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", + "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==" + }, + "oas-validator": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz", + "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", + "requires": { + "call-me-maybe": "^1.0.1", + "oas-kit-common": "^1.0.8", + "oas-linter": "^3.2.2", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "reftools": "^1.1.9", + "should": "^13.2.1", + "yaml": "^1.10.0" + } + }, + "openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "peer": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "reftools": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", + "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "requires": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "requires": { + "should-type": "^1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", + "requires": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==" + }, + "should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "requires": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "swagger-combine": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/swagger-combine/-/swagger-combine-1.4.0.tgz", + "integrity": "sha512-nVQPzSGixSJ6U3BSTBYswIbamumNCz1ZXPqnCrXYz6BHlSeOtfGKuyZ+sAWtpOepUFuOu93x+VOIzAxLKK6xYw==", + "requires": { + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0", + "json-schema-ref-parser": "^9.0.9", + "lodash": "^4.17.21", + "minimist": "^1.2.5", + "swagger-parser": "^10.0.3", + "traverse": "^0.6.6", + "url-join": "^4.0.1" + } + }, + "swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", + "requires": { + "@apidevtools/swagger-parser": "10.0.3" + } + }, + "swagger2openapi": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.3.tgz", + "integrity": "sha512-JSFUmXSR7Qx9WwSKCEqaL4oQfhLLCU2r8Zgf30g15FdSkihItZ6fKFnqSsfqQ6MsmnLlcBf8+OhnQHbi1R0ydg==", + "requires": { + "call-me-maybe": "^1.0.1", + "node-fetch": "^2.6.1", + "node-fetch-h2": "^2.3.0", + "node-readfiles": "^0.2.0", + "oas-kit-common": "^1.0.8", + "oas-resolver": "^2.5.2", + "oas-schema-walker": "^1.1.5", + "oas-validator": "^5.0.3", + "reftools": "^1.1.6", + "yaml": "^1.10.0", + "yargs": "^15.3.1" + }, + "dependencies": { + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==" + }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" + }, + "validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + }, + "z-schema": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.4.tgz", + "integrity": "sha512-gm/lx3hDzJNcLwseIeQVm1UcwhWIKpSB4NqH89pTBtFns4k/HDHudsICtvG05Bvw/Mv3jMyk700y5dadueLHdA==", + "requires": { + "commander": "^2.20.3", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + } + } + } +} diff --git a/docs/package.json b/docs/package.json index 342dd1a95..a0e0f7691 100644 --- a/docs/package.json +++ b/docs/package.json @@ -4,11 +4,11 @@ "main": "index.js", "license": "MIT", "scripts": { - "combine": "swagger-combine ./swagger-combine.config.json -o ../tmp-swagger-gen/swagger.yml -f yaml --continueOnConflictingPaths --includeDefinitions", - "convert": "swagger2openapi ../tmp-swagger-gen/swagger.yml --outfile static/openapi.yml --yaml" + "combine": "swagger-combine ./swagger-combine.config.json -o ../tmp-swagger-gen/swagger.yml -f yaml --continueOnConflictingPaths --includeDefinitions", + "convert": "swagger2openapi ../tmp-swagger-gen/swagger.yml --outfile static/openapi.yml --yaml" }, "dependencies": { - "swagger-combine": "^1.4.0", - "swagger2openapi": "^7.0.3" + "swagger-combine": "^1.4.0", + "swagger2openapi": "^7.0.3" } - } \ No newline at end of file +} diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index 6ed2504d1..03e488826 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -112,10 +112,10 @@ paths: format: byte tags: - Query - "/quasarlabs/quasarnode/intergamm/get_port_info/{portID}/{destinationChainID}": + /quasarlabs/quasarnode/qoracle/params: get: - summary: Queries a list of GetPortInfo items. - operationId: GetPortInfo + summary: Params queries the parameters of the module. + operationId: QOracleParams responses: "200": description: A successful response. @@ -124,17 +124,11 @@ paths: schema: type: object properties: - portInfo: + params: + description: params holds all the parameters of this module. type: object - properties: - portID: - type: string - channelID: - type: string - counterpartyChannelID: - type: string - connectionID: - type: string + description: QueryParamsResponse is response type for the Query/Params RPC + method. default: description: An unexpected error response. content: @@ -156,26 +150,160 @@ paths: properties: type_url: type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types that they + + expect it to use in the context of Any. However, for URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally set up a type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. value: type: string format: byte - parameters: - - name: portID - in: path - required: true - schema: - type: string - - name: destinationChainID - in: path - required: true - schema: - type: string + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } tags: - Query - "/quasarlabs/quasarnode/intergamm/ica_address_on_denom_native_zone/{owner}/{denom}": + /quasarlabs/quasarnode/qoracle/pools: get: - summary: Queries a list of ICAAddressOnDenomNativeZone items. - operationId: ICAAddressOnDenomNativeZone + summary: Pools queries the pools collected from pool oracles. + operationId: Pools responses: "200": description: A successful response. @@ -184,110 +312,216 @@ paths: schema: type: object properties: - icaAddress: - type: string - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: + pools: type: array items: type: object properties: - type_url: + id: type: string - value: + assets: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. + + + NOTE: The amount field is an Int which implements the custom method + + signatures required by gogoproto. + tvl: type: string format: byte - parameters: - - name: owner - in: path - required: true - schema: - type: string - - name: denom - in: path - required: true - schema: - type: string - tags: - - Query - "/quasarlabs/quasarnode/intergamm/ica_address_on_zone/{owner}/{zoneId}": - get: - summary: Queries a list of ICAAddressOnZone items. - operationId: ICAAddressOnZone - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - icaAddress: - type: string - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: + apy: type: string format: byte - parameters: - - name: owner - in: path - required: true - schema: - type: string - - name: zoneId - in: path - required: true - schema: - type: string - tags: - - Query - /quasarlabs/quasarnode/intergamm/interchain_account_from_address: - get: - summary: Queries a list of InterchainAccountFromAddress items. - operationId: InterchainAccountFromAddress - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - interchain_account_address: - type: string + raw: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types that they + + expect it to use in the context of Any. However, for URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally set up a type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol + buffer message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + updated_at: + type: string + format: date-time + description: Pool defines the generalized structure of a liquidity pool coming + from any source chain to qoracle. + pagination: + description: pagination defines the pagination in the response. + type: object + properties: + next_key: + type: string + format: byte + description: >- + next_key is the key to be passed to PageRequest.key to + + query the next page most efficiently. It will be empty if + + there are no more results. + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: QueryPoolsResponse is response type for the Query/Pools RPC method. default: description: An unexpected error response. content: @@ -309,266 +543,226 @@ paths: properties: type_url: type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types that they + + expect it to use in the context of Any. However, for URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally set up a type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. value: type: string format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } parameters: - - name: owner + - name: denom + description: denom filters the pools by their denom. If empty, pools with any + denom returned. in: query required: false schema: type: string - - name: connection_id + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. in: query required: false schema: type: string - tags: - - Query - /quasarlabs/quasarnode/intergamm/params: - get: - summary: Parameters queries the parameters of the module. - operationId: IntergammParams - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - params: - description: params holds all the parameters of this module. - type: object - properties: - quasar_denom_to_native_zone_id_map: - type: object - additionalProperties: - type: string - osmosis_denom_to_quasar_denom_map: - type: object - additionalProperties: - type: string - complete_zone_info_map: - type: object - additionalProperties: - type: object - properties: - zone_route_info: - type: object - properties: - zone_id: - type: string - title: "zone ID: a unique ID for source zone of this route" - chain_id: - type: string - title: chain ID of the source zone - counterparty_zone_id: - type: string - title: "counterparty zone ID: a unique ID for destination zone of this route" - counterparty_chain_id: - type: string - title: chain ID of the destination zone - connection_id: - type: string - title: IBC connection ID from source to destination - port_id: - type: string - title: IBC port ID from source to destination (usually 'transfer') - channel_id: - type: string - title: IBC channel ID from source to destination - counterparty_connection_id: - type: string - title: IBC counterparty connection ID from destination to source - counterparty_port_id: - type: string - title: IBC counterparty port ID from destination to source (usually 'transfer') - counterparty_channel_id: - type: string - title: IBC counterparty channel ID from destination to source - counterparty_version: - type: string - title: IBC counterparty version - next_zone_route_map: - type: object - additionalProperties: - type: object - properties: - zone_id: - type: string - title: "zone ID: a unique ID for source zone of this route" - chain_id: - type: string - title: chain ID of the source zone - counterparty_zone_id: - type: string - title: "counterparty zone ID: a unique ID for destination zone of this route" - counterparty_chain_id: - type: string - title: chain ID of the destination zone - connection_id: - type: string - title: IBC connection ID from source to destination - port_id: - type: string - title: IBC port ID from source to destination (usually 'transfer') - channel_id: - type: string - title: IBC channel ID from source to destination - counterparty_connection_id: - type: string - title: IBC counterparty connection ID from destination to source - counterparty_port_id: - type: string - title: IBC counterparty port ID from destination to source (usually 'transfer') - counterparty_channel_id: - type: string - title: IBC counterparty channel ID from destination to source - counterparty_version: - type: string - title: IBC counterparty version - title: IntermediateReceiver - description: QueryParamsResponse is response type for the Query/Params RPC - method. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - tags: - - Query - /quasarlabs/quasarnode/orion/list_active_lps: - get: - summary: Queries a list of ListActiveLps items. - operationId: ListActiveLps - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - lpIds: - type: array - items: - type: string - format: uint64 - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - tags: - - Query - /quasarlabs/quasarnode/orion/list_module_accounts: - get: - summary: Queries a list of ListModuleAccounts items. - operationId: ListModuleAccounts - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - accInfo: - type: array - items: - type: object - properties: - name: - type: string - account: - type: string - balance: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + It is less efficient than using key. Only one of offset or key should - NOTE: The amount field is an Int which implements the custom method + be set. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. - signatures required by gogoproto. - title: AccountInfo is used for orion module reserve account detail - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte + If left empty it will default to a value to be set by each app. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in UIs. + + count_total is only respected when offset is used. It is ignored when key + + is set. + in: query + required: false + schema: + type: boolean + - name: pagination.reverse + description: >- + reverse is set to true if results are to be returned in the + descending order. + + + Since: cosmos-sdk 0.43 + in: query + required: false + schema: + type: boolean tags: - Query - /quasarlabs/quasarnode/orion/lp_epoch_pairs: + /quasarlabs/quasarnode/qvesting/accounts: get: - summary: Queries a list of LpEpochPairs items. - operationId: LpEpochPairs + summary: VestingAccounts returns all the existing vesting accounts + operationId: VestingAccounts responses: "200": description: A successful response. @@ -577,7731 +771,2511 @@ paths: schema: type: object properties: - lpEpochPairs: - type: array - items: - type: object - properties: - lpId: - type: string - format: uint64 - epochDay: - type: string - format: uint64 - description: LpEpochPair indicates the epoch day on which lpId was created. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: + accounts: type: array items: type: object properties: type_url: type: string - value: - type: string - format: byte - tags: - - Query - /quasarlabs/quasarnode/orion/lp_position: - get: - summary: Queries a LpPosition by index. - operationId: LpPosition - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - LpPosition: - type: object - properties: - seqNo: - type: string - format: uint64 - lpID: - type: string - format: uint64 - lockID: - type: string - format: uint64 - state: - type: string - enum: - - INIT - - JOINING - - JOINED - - JOIN_FAILED - - JOINING_TIMEOUT - - EXITING - - EXITED - - EXIT_FAILED - - EXITING_TIMEOUT - - SETTLED - default: INIT - startTime: - type: string - format: date-time - bondingStartEpochDay: - type: string - format: uint64 - bondDuration: - type: string - format: uint64 - unbondingStartEpochDay: - type: string - format: uint64 - unbondingDuration: - type: string - format: uint64 - poolID: - type: string - format: uint64 - lptoken: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. + description: >- + A URL/resource name that uniquely identifies the + type of the serialized + protocol buffer message. This string must contain at least - NOTE: The amount field is an Int which implements the custom method + one "/" character. The last segment of the URL's path must represent - signatures required by gogoproto. - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. + the fully qualified name of the type (as in + `path/google.protobuf.Duration`). The name should be in a canonical form - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - gaugelocks: - type: array - items: - type: object - properties: - gaugeID: - type: string - format: uint64 - isActive: - type: boolean - lockupDuration: - type: string - expectedApy: - type: string - startTime: - type: string - format: date-time - title: >- - GaugeLockInfo object is used to save the lockup - period, associated approx apy - - and state whether it is active, and start time of this gauge to check the expected aPY - - on any given day. Multiple gaugeLockInfo objects will be associated with each LPPosition - description: >- - LpPosition is used by the strategy during the the Lping - activity. - - Whenever orion module creates an LP position; an object of LpPosition will be created - - for book keeping in the KV store. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: lpId - in: query - required: false - schema: - type: string - format: uint64 - tags: - - Query - /quasarlabs/quasarnode/orion/lp_stat: - get: - summary: Queries a LpStat by index. - operationId: LpStat - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - LpStat: - type: object - properties: - lpCount: - type: string - format: uint64 - totalLPCoins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - title: >- - LpStat is used to do the book keeping of Lping activity on - a given epochday. - - Which includes, total number of Lping position and total LP tokens as []sdk.Coin - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: epochDay - in: query - required: false - schema: - type: string - format: uint64 - tags: - - Query - /quasarlabs/quasarnode/orion/params: - get: - summary: Parameters queries the parameters of the module. - operationId: OrionParams - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - params: - description: params holds all the parameters of this module. - type: object - properties: - perf_fee_per: - type: string - mgmt_fee_per: - type: string - lp_epoch_id: - type: string - destination_chain_id: - type: string - enabled: - type: boolean - white_listed_pools: - type: array - items: - type: string - format: uint64 - osmosis_local_info: - type: object - properties: - local_zone_id: - type: string - connection_id: - type: string - chain_id: - type: string - description: Local Information of the other zone in the intergamm module. - description: QueryParamsResponse is response type for the Query/Params RPC - method. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - tags: - - Query - /quasarlabs/quasarnode/orion/reserve_balance_all: - get: - summary: Queries a list of ReserveBalanceAll items. - operationId: ReserveBalanceAll - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - accInfo: - type: array - items: - type: object - properties: - name: - type: string - account: - type: string - balance: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - title: AccountInfo is used for orion module reserve account detail - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - tags: - - Query - /quasarlabs/quasarnode/orion/reward_collection: - get: - summary: Queries a RewardCollection by index. - operationId: RewardCollection - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - RewardCollection: - type: object - properties: - timeCollected: - type: string - format: date-time - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - description: >- - RewardCollection is used to do the book keeping of the - reward - - collected from the osmosis on a given epochday. This is further used for the approx distribution. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: epochDay - in: query - required: false - schema: - type: string - format: uint64 - tags: - - Query - "/quasarlabs/quasarnode/qbank/get_all_depsoit_infos/{vaultID}": - get: - summary: Queries a list of GetAllDepsoitInfos items. - operationId: GetAllDepsoitInfos - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - depositInfos: - type: array - items: - type: object - properties: - vaultID: - type: string - epochDay: - type: string - format: uint64 - lockupPeriod: - type: string - enum: - - Invalid - - Days_7 - - Days_21 - - Months_1 - - Months_3 - default: Invalid - title: LockupTypes defines different types of locktypes to be used in the system - for users deposit - depositorAccAddress: - type: string - coin: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - title: DepositInfo represents the state of a particular deposit - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: vaultID - in: path - required: true - schema: - type: string - tags: - - Query - /quasarlabs/quasarnode/qbank/params: - get: - summary: Parameters queries the parameters of the module. - operationId: QBankParams - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - params: - description: params holds all the parameters of this module. - type: object - properties: - enabled: - type: boolean - min_orion_epoch_denom_dollar_deposit: - type: string - orion_epoch_identifier: - type: string - white_listed_denoms_in_orion: - type: array - items: - type: object - properties: - origin_name: - type: string - onehop_quasar: - type: string - onehop_osmo: - type: string - description: QueryParamsResponse is response type for the Query/Params RPC - method. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - tags: - - Query - "/quasarlabs/quasarnode/qbank/total_claimed/{userAcc}/{vaultID}": - get: - summary: Queries a list of TotalClaimed items. - operationId: TotalClaimed - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - coins: - type: object - properties: - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - description: QCoins defines encoding/decoding for the slice of sdk.coins to be - used in KV stores. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: userAcc - in: path - required: true - schema: - type: string - - name: vaultID - in: path - required: true - schema: - type: string - tags: - - Query - "/quasarlabs/quasarnode/qbank/total_withdraw/{userAcc}/{vaultID}": - get: - summary: Queries a list of TotalWithdraw items. - operationId: TotalWithdraw - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - coins: - type: object - properties: - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - description: QCoins defines encoding/decoding for the slice of sdk.coins to be - used in KV stores. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: userAcc - in: path - required: true - schema: - type: string - - name: vaultID - in: path - required: true - schema: - type: string - tags: - - Query - "/quasarlabs/quasarnode/qbank/user_claim_rewards/{userAcc}": - get: - summary: Queries a list of UserClaimRewards items. - operationId: UserClaimRewards - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - coins: - type: object - properties: - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - description: QCoins defines encoding/decoding for the slice of sdk.coins to be - used in KV stores. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: userAcc - in: path - required: true - schema: - type: string - tags: - - Query - "/quasarlabs/quasarnode/qbank/user_denom_deposit/{userAcc}": - get: - summary: Queries a list of UserDenomDeposit items. - operationId: UserDenomDeposit - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - amount: - type: string - format: uint64 - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: userAcc - in: path - required: true - schema: - type: string - - name: denom - in: query - required: false - schema: - type: string - tags: - - Query - "/quasarlabs/quasarnode/qbank/user_deposit/{userAcc}": - get: - summary: Queries a list of UserDeposit items. - operationId: UserDeposit - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - coins: - type: object - properties: - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - description: QCoins defines encoding/decoding for the slice of sdk.coins to be - used in KV stores. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: userAcc - in: path - required: true - schema: - type: string - tags: - - Query - "/quasarlabs/quasarnode/qbank/withdrawable/{userAccount}/{denom}": - get: - summary: Queries a list of Withdrawable items. - operationId: Withdrawable - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - coin: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: userAccount - in: path - required: true - schema: - type: string - - name: denom - in: path - required: true - schema: - type: string - tags: - - Query - /quasarlabs/quasarnode/qoracle/oracle_prices: - get: - summary: Queries a list of OraclePrices items. - operationId: OraclePrices - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - prices: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - DecCoin defines a token with a denomination and a - decimal amount. - - - NOTE: The amount field is an Dec which implements the custom method - - signatures required by gogoproto. - updated_at_height: - type: string - format: int64 - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /quasarlabs/quasarnode/qoracle/osmosis/chain_params: - get: - summary: Queries a list of OsmosisChainParams items. - operationId: OsmosisChainParams - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - epochs_info: - type: array - items: - type: object - properties: - identifier: - type: string - description: identifier is a unique reference to this particular timer. - start_time: - type: string - format: date-time - description: >- - start_time is the time at which the timer first ever - ticks. - - If start_time is in the future, the epoch will not begin until the start - - time. - duration: - type: string - description: >- - duration is the time in between epoch ticks. - - In order for intended behavior to be met, duration should - - be greater than the chains expected block time. - - Duration must be non-zero. - current_epoch: - type: string - format: int64 - description: >- - current_epoch is the current epoch number, or in - other words, - - how many times has the timer 'ticked'. - - The first tick (current_epoch=1) is defined as - - the first block whose blocktime is greater than the EpochInfo start_time. - current_epoch_start_time: - type: string - format: date-time - description: >- - current_epoch_start_time describes the start time of - the current timer - - interval. The interval is (current_epoch_start_time, - - current_epoch_start_time + duration] When the timer ticks, this is set to - - current_epoch_start_time = last_epoch_start_time + duration only one timer - - tick for a given identifier can occur per block. - - - NOTE! The current_epoch_start_time may diverge significantly from the - - wall-clock time the epoch began at. Wall-clock time of epoch start may be - - >> current_epoch_start_time. Suppose current_epoch_start_time = 10, - - duration = 5. Suppose the chain goes offline at t=14, and comes back online - - at t=30, and produces blocks at every successive time. (t=31, 32, etc.) - - * The t=30 block will start the epoch for (10, 15] - - * The t=31 block will start the epoch for (15, 20] - - * The t=32 block will start the epoch for (20, 25] - - * The t=33 block will start the epoch for (25, 30] - - * The t=34 block will start the epoch for (30, 35] - - * The **t=36** block will start the epoch for (35, 40] - epoch_counting_started: - type: boolean - description: >- - epoch_counting_started is a boolean, that indicates - whether this - - epoch timer has began yet. - current_epoch_start_height: - type: string - format: int64 - title: >- - current_epoch_start_height is the block height at - which the current epoch - - started. (The block height at which the timer last ticked) - description: |- - EpochInfo is a struct that describes the data going into - a timer defined by the x/epochs module. - lockable_durations: - type: array - items: - type: string - format: int64 - mint_params: - type: object - properties: - mint_denom: - type: string - description: mint_denom is the denom of the coin to mint. - genesis_epoch_provisions: - type: string - description: genesis_epoch_provisions epoch provisions from the first epoch. - epoch_identifier: - type: string - description: epoch_identifier mint epoch identifier e.g. (day, week). - reduction_period_in_epochs: - type: string - format: int64 - description: >- - reduction_period_in_epochs the number of epochs it - takes - - to reduce the rewards. - reduction_factor: - type: string - description: >- - reduction_factor is the reduction multiplier to - execute - - at the end of each period set by reduction_period_in_epochs. - distribution_proportions: - description: >- - distribution_proportions defines the distribution - proportions of the minted - - denom. In other words, defines which stakeholders will receive the minted - - denoms and how much. - type: object - properties: - staking: - type: string - description: >- - staking defines the proportion of the minted - mint_denom that is to be - - allocated as staking rewards. - pool_incentives: - type: string - description: >- - pool_incentives defines the proportion of the - minted mint_denom that is - - to be allocated as pool incentives. - developer_rewards: - type: string - description: >- - developer_rewards defines the proportion of the - minted mint_denom that is - - to be allocated to developer rewards address. - community_pool: - type: string - description: >- - community_pool defines the proportion of the - minted mint_denom that is - - to be allocated to the community pool. - weighted_developer_rewards_receivers: - type: array - items: - type: object - properties: - address: - type: string - weight: - type: string - description: >- - WeightedAddress represents an address with a weight - assigned to it. - - The weight is used to determine the proportion of the total minted - - tokens to be minted to the address. - description: >- - weighted_developer_rewards_receivers is the address to - receive developer - - rewards with weights assignedt to each address. The final amount that each - - address receives is: epoch_provisions * - - distribution_proportions.developer_rewards * Address's Weight. - minting_rewards_distribution_start_epoch: - type: string - format: int64 - title: >- - minting_rewards_distribution_start_epoch start epoch - to distribute minting - - rewards - description: Params holds parameters for the x/mint module. - mint_epoch_provisions: - type: string - distr_info: - type: object - properties: - total_weight: - type: string - records: - type: array - items: - type: object - properties: - gauge_id: - type: string - format: uint64 - weight: - type: string - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /quasarlabs/quasarnode/qoracle/osmosis/incentivized_pools: - get: - summary: Queries a list of OsmosisIncentivizedPools items. - operationId: OsmosisIncentivizedPools - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - incentivized_pools: - type: array - items: - type: object - properties: - pool_id: - type: string - format: uint64 - lockable_duration: - type: string - gauge_id: - type: string - format: uint64 - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /quasarlabs/quasarnode/qoracle/osmosis/pools: - get: - summary: Queries a list of OsmosisPools items. - operationId: OsmosisPools - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - pools: - type: array - items: - type: object - properties: - pool_info: - type: object - properties: - address: - type: string - id: - type: string - format: uint64 - pool_params: - type: object - properties: - swap_fee: - type: string - exit_fee: - type: string - smooth_weight_change_params: - type: object - properties: - start_time: - type: string - format: date-time - description: >- - The start time for beginning the weight - change. - - If a parameter change / pool instantiation leaves this blank, - - it should be generated by the state_machine as the current time. - duration: - type: string - title: Duration for the weights to change over - initial_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, - - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that - combines the amount of the - - token in the pool, and its balancer weight. - - This is an awkward packaging of data, - - and should be revisited in a future state migration. - description: >- - The initial pool weights. These are - copied from the pool's settings - - at the time of weight change instantiation. - - The amount PoolAsset.token.amount field is ignored if present, - - future type refactorings should just have a type with the denom & weight - - here. - target_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, - - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that - combines the amount of the - - token in the pool, and its balancer weight. - - This is an awkward packaging of data, - - and should be revisited in a future state migration. - description: >- - The target pool weights. The pool - weights will change linearly with - respect - - to time between start_time, and start_time + duration. The amount - - PoolAsset.token.amount field is ignored if present, future type - - refactorings should just have a type with the denom & weight here. - title: >- - Parameters for changing the weights in a - balancer pool smoothly from - - a start weight and end weight over a period of time. - - Currently, the only smooth change supported is linear changing between - - the two weights, but more types may be added in the future. - - When these parameters are set, the weight w(t) for pool time `t` is the - - following: - t <= start_time: w(t) = initial_pool_weights - start_time < t <= start_time + duration: - w(t) = initial_pool_weights + (t - start_time) * - (target_pool_weights - initial_pool_weights) / (duration) - t > start_time + duration: w(t) = target_pool_weights - description: >- - PoolParams defined the parameters that will be - managed by the pool - - governance in the future. This params are not managed by the chain - - governance. Instead they will be managed by the token holders of the pool. - - The pool's token holders are specified in future_pool_governor. - future_pool_governor: - type: string - title: >- - This string specifies who will govern the pool - in the future. - - Valid forms of this are: - - {token name},{duration} - - {duration} - - where {token name} if specified is the token which determines the - - governor, and if not specified is the LP token for this pool.duration is - - a time specified as 0w,1w,2w, etc. which specifies how long the token - - would need to be locked up to count in governance. 0w means no lockup. - - TODO: Further improve these docs - total_shares: - title: sum of all LP tokens sent out - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - pool_assets: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, - - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines - the amount of the - - token in the pool, and its balancer weight. - - This is an awkward packaging of data, - - and should be revisited in a future state migration. - title: >- - These are assumed to be sorted by denomiation. - - They contain the pool asset and the information about the weight - total_weight: - type: string - title: sum of all non-normalized pool weights - metrics: - type: object - properties: - apy: - type: string - format: byte - tvl: - type: string - format: byte - pagination: - type: object - properties: - next_key: - type: string - format: byte - description: >- - next_key is the key to be passed to PageRequest.key to - - query the next page most efficiently. It will be empty if - - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages - where the - - corresponding request message has used PageRequest. - - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - schema: - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key should - - be set. - in: query - required: false - schema: - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - schema: - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in UIs. - - count_total is only respected when offset is used. It is ignored when key - - is set. - in: query - required: false - schema: - type: boolean - - name: pagination.reverse - description: >- - reverse is set to true if results are to be returned in the - descending order. - - - Since: cosmos-sdk 0.43 - in: query - required: false - schema: - type: boolean - tags: - - Query - /quasarlabs/quasarnode/qoracle/params: - get: - summary: Parameters queries the parameters of the module. - operationId: QOracleParams - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - params: - description: params holds all the parameters of this module. - type: object - properties: - bandchain_params: - type: object - properties: - oracle_ibc_params: - type: object - properties: - authorized_channel: - type: string - timeout_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at - each height while keeping - - RevisionNumber the same. However some consensus algorithms may choose to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so that - - height continues to be monitonically increasing even as the RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes of updating and - - freezing clients - timeout_timestamp: - type: string - format: uint64 - coin_rates_params: - type: object - properties: - epoch_identifier: - type: string - symbols: - type: array - items: - type: string - script_params: - type: object - properties: - script_id: - type: string - format: uint64 - ask_count: - type: string - format: uint64 - min_count: - type: string - format: uint64 - fee_limit: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination - and an amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - prepare_gas: - type: string - format: uint64 - execute_gas: - type: string - format: uint64 - osmosis_params: - type: object - properties: - icq_params: - type: object - properties: - authorized_channel: - type: string - timeout_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at - each height while keeping - - RevisionNumber the same. However some consensus algorithms may choose to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so that - - height continues to be monitonically increasing even as the RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes of updating and - - freezing clients - timeout_timestamp: - type: string - format: uint64 - epoch_identifier: - type: string - denom_price_mappings: - type: array - items: - type: object - properties: - denom: - type: string - oracle_denom: - type: string - multiplier: - type: string - oneHopDenomMap: - type: array - items: - type: object - properties: - originName: - type: string - quasar: - type: string - osmo: - type: string - description: QueryParamsResponse is response type for the Query/Params RPC - method. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /quasarlabs/quasarnode/qoracle/state: - get: - summary: Queries a list of State items. - operationId: State - responses: - "200": - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - coin_rates_state: - type: object - properties: - call_data: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - request_packet_sequence: - type: string - format: uint64 - oracle_request_id: - type: string - format: uint64 - result_packet_sequence: - type: string - format: uint64 - result: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - failed: - type: boolean - updated_at_height: - type: string - format: int64 - osmosis_params_request_state: - type: object - properties: - packet_sequence: - type: string - format: uint64 - acknowledged: - type: boolean - failed: - type: boolean - updated_at_height: - type: string - format: int64 - osmosis_incentivized_pools_state: - type: object - properties: - packet_sequence: - type: string - format: uint64 - acknowledged: - type: boolean - failed: - type: boolean - updated_at_height: - type: string - format: int64 - osmosis_pools_state: - type: object - properties: - packet_sequence: - type: string - format: uint64 - acknowledged: - type: boolean - failed: - type: boolean - updated_at_height: - type: string - format: int64 - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - tags: - - Query - /quasarlabs/quasarnode/qvesting/params: - get: - summary: Parameters queries the parameters of the module. - operationId: QVestingParams - responses: - '200': - description: A successful response. - content: - "*/*": - schema: - type: object - properties: - params: - description: params holds all the parameters of this module. - type: object - description: >- - QueryParamsResponse is response type for the Query/Params RPC - method. - default: - description: An unexpected error response. - content: - "*/*": - schema: - type: object - properties: - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - '@type': - type: string - additionalProperties: {} - tags: - - Query - /quasarlabs/quasarnode/qvesting/spendable_balances/{address}: - get: - summary: SpendableBalances queries the spenable balance of all coins for a single account. - operationId: SpendableBalances - responses: - '200': - description: A successful response. - default: - description: An unexpected error response. - parameters: - - name: address - description: address is the address to query spendable balances for. - in: path - required: true - schema: - type: string - - name: pagination.key - description: key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set. - in: query - required: false - schema: - type: string - format: byte - - name: pagination.offset - description: offset is a numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set. - in: query - required: false - schema: - type: string - format: uint64 - - name: pagination.limit - description: limit is the total number of results to be returned in the result page. If left empty it will default to a value to be set by each app. - in: query - required: false - schema: - type: string - format: uint64 - - name: pagination.count_total - description: count_total is set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. count_total is only respected when offset is used. It is ignored when key is set. - in: query - required: false - schema: - type: boolean - - name: pagination.reverse - description: reverse is set to true if results are to be returned in the descending order. - in: query - required: false - schema: - type: boolean - tags: - - Query - /quasarlabs/quasarnode/qvesting/accounts: - get: - summary: VestingAccounts returns all the existing vesting accounts - operationId: VestingAccounts - responses: - '200': - description: A successful response. - default: - description: An unexpected error response. - parameters: - - name: pagination.key - description: key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set. - in: query - required: false - schema: - type: string - format: byte - - name: pagination.offset - description: offset is a numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set. - in: query - required: false - schema: - type: string - format: uint64 - - name: pagination.limit - description: limit is the total number of results to be returned in the result page. If left empty it will default to a value to be set by each app. - in: query - required: false - schema: - type: string - format: uint64 - - name: pagination.count_total - description: count_total is set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. count_total is only respected when offset is used. It is ignored when key is set. - in: query - required: false - schema: - type: boolean - - name: pagination.reverse - description: reverse is set to true if results are to be returned in the descending order. - in: query - required: false - schema: - type: boolean - tags: - - Query - /quasarlabs/quasarnode/qvesting/locked_supply/{denom}: - get: - summary: VestingLockedSupply returns the locked supply for a given denom - operationId: VestingLockedSupply - responses: - '200': - description: A successful response. - default: - description: An unexpected error response. - parameters: - - name: denom - description: denom is the denom to query locked supply for. - in: path - required: true - schema: - type: string - tags: - - Query - -components: - schemas: - google.protobuf.Any: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". - - - - JSON - - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - - representation, that representation will be embedded adding a field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - grpc.gateway.runtime.Error: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that they - - expect it to use in the context of Any. However, for URLs which use the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - - protobuf release, and it is not used for type URLs beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in the form - - of utility functions or additional generated methods of the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - - 'type.googleapis.com/full.type.name' as the type URL and the unpack - - methods only use the fully qualified type name after the last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield type - - name "y.z". + (e.g., leading "." is not accepted). + In practice, teams usually precompile into the binary all types that they - JSON + expect it to use in the context of Any. However, for URLs which use the + scheme `http`, `https`, or no scheme, one can optionally set up a type - The JSON representation of an `Any` value uses the regular + server that maps type URLs to message definitions as follows: - representation of the deserialized, embedded message, with an - additional field `@type` which contains the type URL. Example: + * If no scheme is provided, `https` is assumed. - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } + Note: this functionality is not currently available in the official - If the embedded message type is well-known and has a custom JSON + protobuf release, and it is not used for type URLs beginning with - representation, that representation will be embedded adding a field + type.googleapis.com. - `value` which holds the custom JSON in addition to the `@type` - field. Example (for message [google.protobuf.Duration][]): + Schemes other than `http`, `https` (or the empty scheme) might be - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - quasarlabs.quasarnode.epochs.EpochInfo: - type: object - properties: - identifier: - type: string - start_time: - type: string - format: date-time - duration: - type: string - current_epoch: - type: string - format: int64 - current_epoch_start_time: - type: string - format: date-time - epoch_counting_started: - type: boolean - current_epoch_start_height: - type: string - format: int64 - quasarlabs.quasarnode.epochs.QueryCurrentEpochResponse: - type: object - properties: - current_epoch: - type: string - format: int64 - quasarlabs.quasarnode.epochs.QueryEpochsInfoResponse: - type: object - properties: - epochs: - type: array - items: - type: object - properties: - identifier: - type: string - start_time: - type: string - format: date-time - duration: - type: string - current_epoch: - type: string - format: int64 - current_epoch_start_time: - type: string - format: date-time - epoch_counting_started: - type: boolean - current_epoch_start_height: - type: string - format: int64 - quasarlabs.quasarnode.intergamm.Params: - type: object - properties: - quasar_denom_to_native_zone_id_map: - type: object - additionalProperties: - type: string - osmosis_denom_to_quasar_denom_map: - type: object - additionalProperties: - type: string - complete_zone_info_map: - type: object - additionalProperties: - type: object - properties: - zone_route_info: - type: object - properties: - zone_id: - type: string - title: "zone ID: a unique ID for source zone of this route" - chain_id: - type: string - title: chain ID of the source zone - counterparty_zone_id: - type: string - title: "counterparty zone ID: a unique ID for destination zone of this route" - counterparty_chain_id: - type: string - title: chain ID of the destination zone - connection_id: - type: string - title: IBC connection ID from source to destination - port_id: - type: string - title: IBC port ID from source to destination (usually 'transfer') - channel_id: - type: string - title: IBC channel ID from source to destination - counterparty_connection_id: - type: string - title: IBC counterparty connection ID from destination to source - counterparty_port_id: - type: string - title: IBC counterparty port ID from destination to source (usually 'transfer') - counterparty_channel_id: - type: string - title: IBC counterparty channel ID from destination to source - counterparty_version: - type: string - title: IBC counterparty version - next_zone_route_map: - type: object - additionalProperties: - type: object - properties: - zone_id: - type: string - title: "zone ID: a unique ID for source zone of this route" - chain_id: - type: string - title: chain ID of the source zone - counterparty_zone_id: - type: string - title: "counterparty zone ID: a unique ID for destination zone of this route" - counterparty_chain_id: - type: string - title: chain ID of the destination zone - connection_id: - type: string - title: IBC connection ID from source to destination - port_id: - type: string - title: IBC port ID from source to destination (usually 'transfer') - channel_id: - type: string - title: IBC channel ID from source to destination - counterparty_connection_id: - type: string - title: IBC counterparty connection ID from destination to source - counterparty_port_id: - type: string - title: IBC counterparty port ID from destination to source (usually 'transfer') - counterparty_channel_id: - type: string - title: IBC counterparty channel ID from destination to source - counterparty_version: - type: string - title: IBC counterparty version - title: IntermediateReceiver - description: Params defines the parameters for the module. - quasarlabs.quasarnode.intergamm.PortInfo: - type: object - properties: - portID: - type: string - channelID: - type: string - counterpartyChannelID: - type: string - connectionID: - type: string - quasarlabs.quasarnode.intergamm.QueryGetPortInfoResponse: - type: object - properties: - portInfo: - type: object - properties: - portID: - type: string - channelID: - type: string - counterpartyChannelID: - type: string - connectionID: - type: string - quasarlabs.quasarnode.intergamm.QueryICAAddressOnDenomNativeZoneResponse: - type: object - properties: - icaAddress: - type: string - quasarlabs.quasarnode.intergamm.QueryICAAddressOnZoneResponse: - type: object - properties: - icaAddress: - type: string - quasarlabs.quasarnode.intergamm.QueryInterchainAccountFromAddressResponse: - type: object - properties: - interchain_account_address: - type: string - quasarlabs.quasarnode.intergamm.QueryParamsResponse: - type: object - properties: - params: - description: params holds all the parameters of this module. - type: object - properties: - quasar_denom_to_native_zone_id_map: - type: object - additionalProperties: - type: string - osmosis_denom_to_quasar_denom_map: - type: object - additionalProperties: - type: string - complete_zone_info_map: - type: object - additionalProperties: - type: object - properties: - zone_route_info: - type: object - properties: - zone_id: - type: string - title: "zone ID: a unique ID for source zone of this route" - chain_id: - type: string - title: chain ID of the source zone - counterparty_zone_id: - type: string - title: "counterparty zone ID: a unique ID for destination zone of this route" - counterparty_chain_id: - type: string - title: chain ID of the destination zone - connection_id: - type: string - title: IBC connection ID from source to destination - port_id: - type: string - title: IBC port ID from source to destination (usually 'transfer') - channel_id: - type: string - title: IBC channel ID from source to destination - counterparty_connection_id: - type: string - title: IBC counterparty connection ID from destination to source - counterparty_port_id: - type: string - title: IBC counterparty port ID from destination to source (usually 'transfer') - counterparty_channel_id: - type: string - title: IBC counterparty channel ID from destination to source - counterparty_version: - type: string - title: IBC counterparty version - next_zone_route_map: - type: object - additionalProperties: - type: object - properties: - zone_id: - type: string - title: "zone ID: a unique ID for source zone of this route" - chain_id: - type: string - title: chain ID of the source zone - counterparty_zone_id: - type: string - title: "counterparty zone ID: a unique ID for destination zone of this route" - counterparty_chain_id: - type: string - title: chain ID of the destination zone - connection_id: - type: string - title: IBC connection ID from source to destination - port_id: - type: string - title: IBC port ID from source to destination (usually 'transfer') - channel_id: - type: string - title: IBC channel ID from source to destination - counterparty_connection_id: - type: string - title: IBC counterparty connection ID from destination to source - counterparty_port_id: - type: string - title: IBC counterparty port ID from destination to source (usually 'transfer') - counterparty_channel_id: - type: string - title: IBC counterparty channel ID from destination to source - counterparty_version: + used with implementation specific semantics. + value: type: string - title: IBC counterparty version - title: IntermediateReceiver - description: QueryParamsResponse is response type for the Query/Params RPC method. - quasarlabs.quasarnode.intergamm.ZoneCompleteInfo: - type: object - properties: - zone_route_info: - type: object - properties: - zone_id: - type: string - title: "zone ID: a unique ID for source zone of this route" - chain_id: - type: string - title: chain ID of the source zone - counterparty_zone_id: - type: string - title: "counterparty zone ID: a unique ID for destination zone of this route" - counterparty_chain_id: - type: string - title: chain ID of the destination zone - connection_id: - type: string - title: IBC connection ID from source to destination - port_id: - type: string - title: IBC port ID from source to destination (usually 'transfer') - channel_id: - type: string - title: IBC channel ID from source to destination - counterparty_connection_id: - type: string - title: IBC counterparty connection ID from destination to source - counterparty_port_id: - type: string - title: IBC counterparty port ID from destination to source (usually 'transfer') - counterparty_channel_id: - type: string - title: IBC counterparty channel ID from destination to source - counterparty_version: - type: string - title: IBC counterparty version - next_zone_route_map: - type: object - additionalProperties: - type: object - properties: - zone_id: - type: string - title: "zone ID: a unique ID for source zone of this route" - chain_id: - type: string - title: chain ID of the source zone - counterparty_zone_id: - type: string - title: "counterparty zone ID: a unique ID for destination zone of this route" - counterparty_chain_id: - type: string - title: chain ID of the destination zone - connection_id: - type: string - title: IBC connection ID from source to destination - port_id: - type: string - title: IBC port ID from source to destination (usually 'transfer') - channel_id: - type: string - title: IBC channel ID from source to destination - counterparty_connection_id: - type: string - title: IBC counterparty connection ID from destination to source - counterparty_port_id: - type: string - title: IBC counterparty port ID from destination to source (usually 'transfer') - counterparty_channel_id: - type: string - title: IBC counterparty channel ID from destination to source - counterparty_version: - type: string - title: IBC counterparty version - title: IntermediateReceiver - quasarlabs.quasarnode.intergamm.ZoneRouteInfo: - type: object - properties: - zone_id: - type: string - title: "zone ID: a unique ID for source zone of this route" - chain_id: - type: string - title: chain ID of the source zone - counterparty_zone_id: - type: string - title: "counterparty zone ID: a unique ID for destination zone of this route" - counterparty_chain_id: - type: string - title: chain ID of the destination zone - connection_id: - type: string - title: IBC connection ID from source to destination - port_id: - type: string - title: IBC port ID from source to destination (usually 'transfer') - channel_id: - type: string - title: IBC channel ID from source to destination - counterparty_connection_id: - type: string - title: IBC counterparty connection ID from destination to source - counterparty_port_id: - type: string - title: IBC counterparty port ID from destination to source (usually 'transfer') - counterparty_channel_id: - type: string - title: IBC counterparty channel ID from destination to source - counterparty_version: - type: string - title: IBC counterparty version - cosmos.base.v1beta1.Coin: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - quasarlabs.quasarnode.orion.AccountInfo: - type: object - properties: - name: - type: string - account: - type: string - balance: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + URL that describes the type of the serialized message. - NOTE: The amount field is an Int which implements the custom method + Protobuf library provides support to pack/unpack Any values in the form - signatures required by gogoproto. - title: AccountInfo is used for orion module reserve account detail - quasarlabs.quasarnode.orion.GaugeLockInfo: - type: object - properties: - gaugeID: - type: string - format: uint64 - isActive: - type: boolean - lockupDuration: - type: string - expectedApy: - type: string - startTime: - type: string - format: date-time - title: >- - GaugeLockInfo object is used to save the lockup period, associated - approx apy + of utility functions or additional generated methods of the Any type. - and state whether it is active, and start time of this gauge to check the expected aPY - on any given day. Multiple gaugeLockInfo objects will be associated with each LPPosition - quasarlabs.quasarnode.orion.LpEpochPair: - type: object - properties: - lpId: - type: string - format: uint64 - epochDay: - type: string - format: uint64 - description: LpEpochPair indicates the epoch day on which lpId was created. - quasarlabs.quasarnode.orion.LpPosition: - type: object - properties: - seqNo: - type: string - format: uint64 - lpID: - type: string - format: uint64 - lockID: - type: string - format: uint64 - state: - type: string - enum: - - INIT - - JOINING - - JOINED - - JOIN_FAILED - - JOINING_TIMEOUT - - EXITING - - EXITED - - EXIT_FAILED - - EXITING_TIMEOUT - - SETTLED - default: INIT - startTime: - type: string - format: date-time - bondingStartEpochDay: - type: string - format: uint64 - bondDuration: - type: string - format: uint64 - unbondingStartEpochDay: - type: string - format: uint64 - unbondingDuration: - type: string - format: uint64 - poolID: - type: string - format: uint64 - lptoken: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. + Example 1: Pack and unpack a message in C++. - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + Example 2: Pack and unpack a message in Java. - NOTE: The amount field is an Int which implements the custom method + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - signatures required by gogoproto. - gaugelocks: - type: array - items: - type: object - properties: - gaugeID: - type: string - format: uint64 - isActive: - type: boolean - lockupDuration: - type: string - expectedApy: - type: string - startTime: - type: string - format: date-time - title: >- - GaugeLockInfo object is used to save the lockup period, associated - approx apy + Example 3: Pack and unpack a message in Python. - and state whether it is active, and start time of this gauge to check the expected aPY + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - on any given day. Multiple gaugeLockInfo objects will be associated with each LPPosition - description: >- - LpPosition is used by the strategy during the the Lping activity. + Example 4: Pack and unpack a message in Go - Whenever orion module creates an LP position; an object of LpPosition will be created + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } - for book keeping in the KV store. - quasarlabs.quasarnode.orion.LpStat: - type: object - properties: - lpCount: - type: string - format: uint64 - totalLPCoins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + The pack methods provided by protobuf library will by default use + 'type.googleapis.com/full.type.name' as the type URL and the unpack - NOTE: The amount field is an Int which implements the custom method + methods only use the fully qualified type name after the last '/' - signatures required by gogoproto. - title: >- - LpStat is used to do the book keeping of Lping activity on a given - epochday. - - Which includes, total number of Lping position and total LP tokens as []sdk.Coin - quasarlabs.quasarnode.orion.LpState: - type: string - enum: - - INIT - - JOINING - - JOINED - - JOIN_FAILED - - JOINING_TIMEOUT - - EXITING - - EXITED - - EXIT_FAILED - - EXITING_TIMEOUT - - SETTLED - default: INIT - quasarlabs.quasarnode.orion.Params: - type: object - properties: - perf_fee_per: - type: string - mgmt_fee_per: - type: string - lp_epoch_id: - type: string - destination_chain_id: - type: string - enabled: - type: boolean - white_listed_pools: - type: array - items: - type: string - format: uint64 - osmosis_local_info: - type: object - properties: - local_zone_id: - type: string - connection_id: - type: string - chain_id: - type: string - description: Local Information of the other zone in the intergamm module. - description: Params defines the parameters for the module. - quasarlabs.quasarnode.orion.QueryGetLpPositionResponse: - type: object - properties: - LpPosition: - type: object - properties: - seqNo: - type: string - format: uint64 - lpID: - type: string - format: uint64 - lockID: - type: string - format: uint64 - state: - type: string - enum: - - INIT - - JOINING - - JOINED - - JOIN_FAILED - - JOINING_TIMEOUT - - EXITING - - EXITED - - EXIT_FAILED - - EXITING_TIMEOUT - - SETTLED - default: INIT - startTime: - type: string - format: date-time - bondingStartEpochDay: - type: string - format: uint64 - bondDuration: - type: string - format: uint64 - unbondingStartEpochDay: - type: string - format: uint64 - unbondingDuration: - type: string - format: uint64 - poolID: - type: string - format: uint64 - lptoken: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + in the type URL, for example "foo.bar.com/x/y.z" will yield type + name "y.z". - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + JSON - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - gaugelocks: - type: array - items: - type: object - properties: - gaugeID: - type: string - format: uint64 - isActive: - type: boolean - lockupDuration: - type: string - expectedApy: - type: string - startTime: - type: string - format: date-time - title: >- - GaugeLockInfo object is used to save the lockup period, - associated approx apy + The JSON representation of an `Any` value uses the regular - and state whether it is active, and start time of this gauge to check the expected aPY + representation of the deserialized, embedded message, with an - on any given day. Multiple gaugeLockInfo objects will be associated with each LPPosition - description: >- - LpPosition is used by the strategy during the the Lping activity. + additional field `@type` which contains the type URL. Example: - Whenever orion module creates an LP position; an object of LpPosition will be created + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - for book keeping in the KV store. - quasarlabs.quasarnode.orion.QueryGetLpStatResponse: - type: object - properties: - LpStat: - type: object - properties: - lpCount: - type: string - format: uint64 - totalLPCoins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + If the embedded message type is well-known and has a custom JSON - NOTE: The amount field is an Int which implements the custom method + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: accounts are the existing vesting accounts + pagination: + description: pagination defines the pagination in the response. + type: object + properties: + next_key: + type: string + format: byte + description: >- + next_key is the key to be passed to PageRequest.key to + + query the next page most efficiently. It will be empty if - signatures required by gogoproto. - title: >- - LpStat is used to do the book keeping of Lping activity on a given - epochday. + there are no more results. + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total - Which includes, total number of Lping position and total LP tokens as []sdk.Coin - quasarlabs.quasarnode.orion.QueryGetRewardCollectionResponse: - type: object - properties: - RewardCollection: - type: object - properties: - timeCollected: - type: string - format: date-time - coins: - type: array - items: + was set, its value is undefined otherwise + description: QueryVestingAccountsResponse is the response type for the + Query/Accounts RPC method. + default: + description: An unexpected error response. + content: + "*/*": + schema: type: object properties: - denom: + error: type: string - amount: + code: + type: integer + format: int32 + message: type: string - description: >- - Coin defines a token with a denomination and an amount. + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized + protocol buffer message. This string must contain at least - NOTE: The amount field is an Int which implements the custom method + one "/" character. The last segment of the URL's path must represent - signatures required by gogoproto. - description: >- - RewardCollection is used to do the book keeping of the reward + the fully qualified name of the type (as in - collected from the osmosis on a given epochday. This is further used for the approx distribution. - quasarlabs.quasarnode.orion.QueryListActiveLpsResponse: - type: object - properties: - lpIds: - type: array - items: - type: string - format: uint64 - quasarlabs.quasarnode.orion.QueryListModuleAccountsResponse: - type: object - properties: - accInfo: - type: array - items: - type: object - properties: - name: - type: string - account: - type: string - balance: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + `path/google.protobuf.Duration`). The name should be in a canonical form + (e.g., leading "." is not accepted). - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - title: AccountInfo is used for orion module reserve account detail - quasarlabs.quasarnode.orion.QueryLpEpochPairsResponse: - type: object - properties: - lpEpochPairs: - type: array - items: - type: object - properties: - lpId: - type: string - format: uint64 - epochDay: - type: string - format: uint64 - description: LpEpochPair indicates the epoch day on which lpId was created. - quasarlabs.quasarnode.orion.QueryParamsResponse: - type: object - properties: - params: - description: params holds all the parameters of this module. - type: object - properties: - perf_fee_per: - type: string - mgmt_fee_per: - type: string - lp_epoch_id: - type: string - destination_chain_id: - type: string - enabled: - type: boolean - white_listed_pools: - type: array - items: - type: string - format: uint64 - osmosis_local_info: - type: object - properties: - local_zone_id: - type: string - connection_id: - type: string - chain_id: - type: string - description: Local Information of the other zone in the intergamm module. - description: QueryParamsResponse is response type for the Query/Params RPC method. - quasarlabs.quasarnode.orion.QueryReserveBalanceAllResponse: - type: object - properties: - accInfo: - type: array - items: - type: object - properties: - name: - type: string - account: - type: string - balance: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + In practice, teams usually precompile into the binary all types that they + expect it to use in the context of Any. However, for URLs which use the - NOTE: The amount field is an Int which implements the custom method + scheme `http`, `https`, or no scheme, one can optionally set up a type - signatures required by gogoproto. - title: AccountInfo is used for orion module reserve account detail - quasarlabs.quasarnode.orion.RewardCollection: - type: object - properties: - timeCollected: - type: string - format: date-time - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + server that maps type URLs to message definitions as follows: - NOTE: The amount field is an Int which implements the custom method + * If no scheme is provided, `https` is assumed. - signatures required by gogoproto. - description: >- - RewardCollection is used to do the book keeping of the reward + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - collected from the osmosis on a given epochday. This is further used for the approx distribution. - quasarlabs.quasarnode.orion.ZoneLocalInfo: - type: object - properties: - local_zone_id: - type: string - connection_id: - type: string - chain_id: - type: string - description: Local Information of the other zone in the intergamm module. - quasarlabs.quasarnode.qbank.DepositInfo: - type: object - properties: - vaultID: - type: string - epochDay: - type: string - format: uint64 - lockupPeriod: - type: string - enum: - - Invalid - - Days_7 - - Days_21 - - Months_1 - - Months_3 - default: Invalid - title: LockupTypes defines different types of locktypes to be used in the system - for users deposit - depositorAccAddress: - type: string - coin: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - title: DepositInfo represents the state of a particular deposit - quasarlabs.quasarnode.qbank.LockupTypes: - type: string - enum: - - Invalid - - Days_7 - - Days_21 - - Months_1 - - Months_3 - default: Invalid - title: LockupTypes defines different types of locktypes to be used in the system - for users deposit - quasarlabs.quasarnode.qbank.Params: - type: object - properties: - enabled: - type: boolean - min_orion_epoch_denom_dollar_deposit: - type: string - orion_epoch_identifier: - type: string - white_listed_denoms_in_orion: - type: array - items: - type: object - properties: - origin_name: - type: string - onehop_quasar: - type: string - onehop_osmo: - type: string - description: Params defines the parameters for the module. - quasarlabs.quasarnode.qbank.QCoins: - type: object - properties: - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + Note: this functionality is not currently available in the official + protobuf release, and it is not used for type URLs beginning with - NOTE: The amount field is an Int which implements the custom method + type.googleapis.com. - signatures required by gogoproto. - description: QCoins defines encoding/decoding for the slice of sdk.coins to be - used in KV stores. - quasarlabs.quasarnode.qbank.QueryGetAllDepsoitInfosResponse: - type: object - properties: - depositInfos: - type: array - items: - type: object - properties: - vaultID: - type: string - epochDay: - type: string - format: uint64 - lockupPeriod: - type: string - enum: - - Invalid - - Days_7 - - Days_21 - - Months_1 - - Months_3 - default: Invalid - title: LockupTypes defines different types of locktypes to be used in the system - for users deposit - depositorAccAddress: - type: string - coin: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + Schemes other than `http`, `https` (or the empty scheme) might be - NOTE: The amount field is an Int which implements the custom method + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a - signatures required by gogoproto. - title: DepositInfo represents the state of a particular deposit - quasarlabs.quasarnode.qbank.QueryParamsResponse: - type: object - properties: - params: - description: params holds all the parameters of this module. - type: object - properties: - enabled: - type: boolean - min_orion_epoch_denom_dollar_deposit: - type: string - orion_epoch_identifier: - type: string - white_listed_denoms_in_orion: - type: array - items: - type: object - properties: - origin_name: - type: string - onehop_quasar: - type: string - onehop_osmo: - type: string - description: QueryParamsResponse is response type for the Query/Params RPC method. - quasarlabs.quasarnode.qbank.QueryTotalClaimedResponse: - type: object - properties: - coins: - type: object - properties: - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + URL that describes the type of the serialized message. - NOTE: The amount field is an Int which implements the custom method + Protobuf library provides support to pack/unpack Any values in the form - signatures required by gogoproto. - description: QCoins defines encoding/decoding for the slice of sdk.coins to be - used in KV stores. - quasarlabs.quasarnode.qbank.QueryTotalWithdrawResponse: - type: object - properties: - coins: - type: object - properties: - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + of utility functions or additional generated methods of the Any type. - NOTE: The amount field is an Int which implements the custom method + Example 1: Pack and unpack a message in C++. - signatures required by gogoproto. - description: QCoins defines encoding/decoding for the slice of sdk.coins to be - used in KV stores. - quasarlabs.quasarnode.qbank.QueryUserClaimRewardsResponse: - type: object - properties: - coins: - type: object - properties: - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + Example 2: Pack and unpack a message in Java. - NOTE: The amount field is an Int which implements the custom method + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - signatures required by gogoproto. - description: QCoins defines encoding/decoding for the slice of sdk.coins to be - used in KV stores. - quasarlabs.quasarnode.qbank.QueryUserDenomDepositResponse: - type: object - properties: - amount: - type: string - format: uint64 - quasarlabs.quasarnode.qbank.QueryUserDepositResponse: - type: object - properties: - coins: - type: object - properties: - coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + Example 3: Pack and unpack a message in Python. + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - NOTE: The amount field is an Int which implements the custom method + Example 4: Pack and unpack a message in Go - signatures required by gogoproto. - description: QCoins defines encoding/decoding for the slice of sdk.coins to be - used in KV stores. - quasarlabs.quasarnode.qbank.QueryWithdrawableResponse: - type: object - properties: - coin: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - quasarlabs.quasarnode.qbank.WhiteListedDenomInOrion: - type: object - properties: - origin_name: - type: string - onehop_quasar: - type: string - onehop_osmo: - type: string - cosmos.base.query.v1beta1.PageRequest: - type: object - properties: - key: - type: string - format: byte - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - offset: - type: string - format: uint64 - description: >- - offset is a numeric offset that can be used when key is unavailable. + The pack methods provided by protobuf library will by default use - It is less efficient than using key. Only one of offset or key should + 'type.googleapis.com/full.type.name' as the type URL and the unpack - be set. - limit: - type: string - format: uint64 - description: >- - limit is the total number of results to be returned in the result - page. + methods only use the fully qualified type name after the last '/' - If left empty it will default to a value to be set by each app. - count_total: - type: boolean - description: >- - count_total is set to true to indicate that the result set should - include + in the type URL, for example "foo.bar.com/x/y.z" will yield type - a count of the total number of items available for pagination in UIs. + name "y.z". - count_total is only respected when offset is used. It is ignored when key - is set. - reverse: - type: boolean - description: >- - reverse is set to true if results are to be returned in the - descending order. + JSON - Since: cosmos-sdk 0.43 - description: |- - message SomeRequest { - Foo some_parameter = 1; - PageRequest pagination = 2; - } - title: |- - PageRequest is to be embedded in gRPC request messages for efficient - pagination. Ex: - cosmos.base.query.v1beta1.PageResponse: - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. + The JSON representation of an `Any` value uses the regular - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - cosmos.base.v1beta1.DecCoin: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - DecCoin defines a token with a denomination and a decimal amount. + representation of the deserialized, embedded message, with an - NOTE: The amount field is an Dec which implements the custom method - signatures required by gogoproto. - ibc.core.client.v1.Height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while keeping + additional field `@type` which contains the type URL. Example: - RevisionNumber the same. However some consensus algorithms may choose to + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - reset the height in certain conditions e.g. hard forks, state-machine + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - breaking changes In these cases, the RevisionNumber is incremented so that + If the embedded message type is well-known and has a custom JSON - height continues to be monitonically increasing even as the RevisionHeight + representation, that representation will be embedded adding a field - gets reset - title: >- - Height is a monotonically increasing data type + `value` which holds the custom JSON in addition to the `@type` - that can be compared against another Height for the purposes of updating and + field. Example (for message [google.protobuf.Duration][]): - freezing clients - osmosis.epochs.v1beta1.EpochInfo: - type: object - properties: - identifier: - type: string - description: identifier is a unique reference to this particular timer. - start_time: - type: string - format: date-time + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + schema: + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key should + + be set. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.count_total description: >- - start_time is the time at which the timer first ever ticks. + count_total is set to true to indicate that the result set should + include - If start_time is in the future, the epoch will not begin until the start + a count of the total number of items available for pagination in UIs. - time. - duration: - type: string - description: |- - duration is the time in between epoch ticks. - In order for intended behavior to be met, duration should - be greater than the chains expected block time. - Duration must be non-zero. - current_epoch: - type: string - format: int64 - description: >- - current_epoch is the current epoch number, or in other words, + count_total is only respected when offset is used. It is ignored when key - how many times has the timer 'ticked'. + is set. + in: query + required: false + schema: + type: boolean + - name: pagination.reverse + description: >- + reverse is set to true if results are to be returned in the + descending order. - The first tick (current_epoch=1) is defined as - the first block whose blocktime is greater than the EpochInfo start_time. - current_epoch_start_time: - type: string - format: date-time - description: >- - current_epoch_start_time describes the start time of the current - timer + Since: cosmos-sdk 0.43 + in: query + required: false + schema: + type: boolean + tags: + - Query + "/quasarlabs/quasarnode/qvesting/locked_supply/{denom}": + get: + summary: VestingAccounts returns all the existing vesting accounts + operationId: VestingLockedSupply + responses: + "200": + description: A successful response. + content: + "*/*": + schema: + type: object + properties: + amount: + description: amount is the supply of the coin. + type: object + properties: + denom: + type: string + amount: + type: string + description: QueryVestingAccountsResponse is the response type for the + Query/VestingLockedSupply RPC method. + default: + description: An unexpected error response. + content: + "*/*": + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized - interval. The interval is (current_epoch_start_time, + protocol buffer message. This string must contain at least - current_epoch_start_time + duration] When the timer ticks, this is set to + one "/" character. The last segment of the URL's path must represent - current_epoch_start_time = last_epoch_start_time + duration only one timer + the fully qualified name of the type (as in - tick for a given identifier can occur per block. + `path/google.protobuf.Duration`). The name should be in a canonical form + (e.g., leading "." is not accepted). - NOTE! The current_epoch_start_time may diverge significantly from the - wall-clock time the epoch began at. Wall-clock time of epoch start may be + In practice, teams usually precompile into the binary all types that they - >> current_epoch_start_time. Suppose current_epoch_start_time = 10, + expect it to use in the context of Any. However, for URLs which use the - duration = 5. Suppose the chain goes offline at t=14, and comes back online + scheme `http`, `https`, or no scheme, one can optionally set up a type - at t=30, and produces blocks at every successive time. (t=31, 32, etc.) + server that maps type URLs to message definitions as follows: - * The t=30 block will start the epoch for (10, 15] - * The t=31 block will start the epoch for (15, 20] + * If no scheme is provided, `https` is assumed. - * The t=32 block will start the epoch for (20, 25] + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - * The t=33 block will start the epoch for (25, 30] + Note: this functionality is not currently available in the official - * The t=34 block will start the epoch for (30, 35] + protobuf release, and it is not used for type URLs beginning with - * The **t=36** block will start the epoch for (35, 40] - epoch_counting_started: - type: boolean - description: |- - epoch_counting_started is a boolean, that indicates whether this - epoch timer has began yet. - current_epoch_start_height: - type: string - format: int64 - title: >- - current_epoch_start_height is the block height at which the current - epoch + type.googleapis.com. - started. (The block height at which the timer last ticked) - description: |- - EpochInfo is a struct that describes the data going into - a timer defined by the x/epochs module. - osmosis.gamm.v1beta1.Pool: - type: object - properties: - address: - type: string - id: - type: string - format: uint64 - pool_params: - type: object - properties: - swap_fee: - type: string - exit_fee: - type: string - smooth_weight_change_params: - type: object - properties: - start_time: - type: string - format: date-time - description: >- - The start time for beginning the weight change. - If a parameter change / pool instantiation leaves this blank, + Schemes other than `http`, `https` (or the empty scheme) might be - it should be generated by the state_machine as the current time. - duration: - type: string - title: Duration for the weights to change over - initial_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, - - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines the amount - of the + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a - token in the pool, and its balancer weight. + URL that describes the type of the serialized message. - This is an awkward packaging of data, - and should be revisited in a future state migration. - description: >- - The initial pool weights. These are copied from the pool's - settings + Protobuf library provides support to pack/unpack Any values in the form - at the time of weight change instantiation. + of utility functions or additional generated methods of the Any type. - The amount PoolAsset.token.amount field is ignored if present, - future type refactorings should just have a type with the denom & weight + Example 1: Pack and unpack a message in C++. - here. - target_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, - - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines the amount - of the + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - token in the pool, and its balancer weight. + Example 2: Pack and unpack a message in Java. - This is an awkward packaging of data, + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - and should be revisited in a future state migration. - description: >- - The target pool weights. The pool weights will change - linearly with respect + Example 3: Pack and unpack a message in Python. - to time between start_time, and start_time + duration. The amount + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - PoolAsset.token.amount field is ignored if present, future type + Example 4: Pack and unpack a message in Go - refactorings should just have a type with the denom & weight here. - title: >- - Parameters for changing the weights in a balancer pool smoothly - from + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } - a start weight and end weight over a period of time. + The pack methods provided by protobuf library will by default use - Currently, the only smooth change supported is linear changing between + 'type.googleapis.com/full.type.name' as the type URL and the unpack - the two weights, but more types may be added in the future. + methods only use the fully qualified type name after the last '/' - When these parameters are set, the weight w(t) for pool time `t` is the + in the type URL, for example "foo.bar.com/x/y.z" will yield type - following: - t <= start_time: w(t) = initial_pool_weights - start_time < t <= start_time + duration: - w(t) = initial_pool_weights + (t - start_time) * - (target_pool_weights - initial_pool_weights) / (duration) - t > start_time + duration: w(t) = target_pool_weights - description: >- - PoolParams defined the parameters that will be managed by the pool + name "y.z". - governance in the future. This params are not managed by the chain - governance. Instead they will be managed by the token holders of the pool. - The pool's token holders are specified in future_pool_governor. - future_pool_governor: - type: string - title: >- - This string specifies who will govern the pool in the future. + JSON - Valid forms of this are: - {token name},{duration} + The JSON representation of an `Any` value uses the regular - {duration} + representation of the deserialized, embedded message, with an - where {token name} if specified is the token which determines the + additional field `@type` which contains the type URL. Example: - governor, and if not specified is the LP token for this pool.duration is + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - a time specified as 0w,1w,2w, etc. which specifies how long the token + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - would need to be locked up to count in governance. 0w means no lockup. + If the embedded message type is well-known and has a custom JSON - TODO: Further improve these docs - total_shares: - title: sum of all LP tokens sent out - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. + representation, that representation will be embedded adding a field - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - pool_assets: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, + `value` which holds the custom JSON in addition to the `@type` - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: |- - Pool asset is an internal struct that combines the amount of the - token in the pool, and its balancer weight. - This is an awkward packaging of data, - and should be revisited in a future state migration. - title: |- - These are assumed to be sorted by denomiation. - They contain the pool asset and the information about the weight - total_weight: - type: string - title: sum of all non-normalized pool weights - osmosis.gamm.v1beta1.PoolAsset: - type: object - properties: - token: - description: >- - Coins we are talking about, + field. Example (for message [google.protobuf.Duration][]): - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: |- - Pool asset is an internal struct that combines the amount of the - token in the pool, and its balancer weight. - This is an awkward packaging of data, - and should be revisited in a future state migration. - osmosis.gamm.v1beta1.PoolParams: - type: object - properties: - swap_fee: - type: string - exit_fee: - type: string - smooth_weight_change_params: - type: object - properties: - start_time: - type: string - format: date-time - description: |- - The start time for beginning the weight change. - If a parameter change / pool instantiation leaves this blank, - it should be generated by the state_machine as the current time. - duration: - type: string - title: Duration for the weights to change over - initial_pool_weights: - type: array - items: + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: denom + description: denom is the coin denom to query locked supply for. + in: path + required: true + schema: + type: string + tags: + - Query + /quasarlabs/quasarnode/qvesting/params: + get: + summary: Parameters queries the parameters of the module. + operationId: QVestingParams + responses: + "200": + description: A successful response. + content: + "*/*": + schema: type: object properties: - token: - description: >- - Coins we are talking about, - - the denomination must be unique amongst all PoolAssets for this pool. + params: + description: params holds all the parameters of this module. type: object - properties: - denom: - type: string - amount: - type: string - weight: + description: QueryParamsResponse is response type for the Query/Params RPC + method. + default: + description: An unexpected error response. + content: + "*/*": + schema: + type: object + properties: + error: type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines the amount of - the - - token in the pool, and its balancer weight. - - This is an awkward packaging of data, - - and should be revisited in a future state migration. - description: >- - The initial pool weights. These are copied from the pool's - settings + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized - at the time of weight change instantiation. + protocol buffer message. This string must contain at least - The amount PoolAsset.token.amount field is ignored if present, + one "/" character. The last segment of the URL's path must represent - future type refactorings should just have a type with the denom & weight + the fully qualified name of the type (as in - here. - target_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, + `path/google.protobuf.Duration`). The name should be in a canonical form - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines the amount of - the + (e.g., leading "." is not accepted). - token in the pool, and its balancer weight. - This is an awkward packaging of data, + In practice, teams usually precompile into the binary all types that they - and should be revisited in a future state migration. - description: >- - The target pool weights. The pool weights will change linearly - with respect + expect it to use in the context of Any. However, for URLs which use the - to time between start_time, and start_time + duration. The amount + scheme `http`, `https`, or no scheme, one can optionally set up a type - PoolAsset.token.amount field is ignored if present, future type + server that maps type URLs to message definitions as follows: - refactorings should just have a type with the denom & weight here. - title: >- - Parameters for changing the weights in a balancer pool smoothly from - a start weight and end weight over a period of time. + * If no scheme is provided, `https` is assumed. - Currently, the only smooth change supported is linear changing between + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - the two weights, but more types may be added in the future. + Note: this functionality is not currently available in the official - When these parameters are set, the weight w(t) for pool time `t` is the + protobuf release, and it is not used for type URLs beginning with - following: - t <= start_time: w(t) = initial_pool_weights - start_time < t <= start_time + duration: - w(t) = initial_pool_weights + (t - start_time) * - (target_pool_weights - initial_pool_weights) / (duration) - t > start_time + duration: w(t) = target_pool_weights - description: >- - PoolParams defined the parameters that will be managed by the pool + type.googleapis.com. - governance in the future. This params are not managed by the chain - governance. Instead they will be managed by the token holders of the pool. + Schemes other than `http`, `https` (or the empty scheme) might be - The pool's token holders are specified in future_pool_governor. - osmosis.gamm.v1beta1.SmoothWeightChangeParams: - type: object - properties: - start_time: - type: string - format: date-time - description: |- - The start time for beginning the weight change. - If a parameter change / pool instantiation leaves this blank, - it should be generated by the state_machine as the current time. - duration: - type: string - title: Duration for the weights to change over - initial_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: |- - Pool asset is an internal struct that combines the amount of the - token in the pool, and its balancer weight. - This is an awkward packaging of data, - and should be revisited in a future state migration. - description: >- - The initial pool weights. These are copied from the pool's settings + URL that describes the type of the serialized message. - at the time of weight change instantiation. - The amount PoolAsset.token.amount field is ignored if present, + Protobuf library provides support to pack/unpack Any values in the form - future type refactorings should just have a type with the denom & weight + of utility functions or additional generated methods of the Any type. - here. - target_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: |- - Pool asset is an internal struct that combines the amount of the - token in the pool, and its balancer weight. - This is an awkward packaging of data, - and should be revisited in a future state migration. - description: >- - The target pool weights. The pool weights will change linearly with - respect + Example 1: Pack and unpack a message in C++. - to time between start_time, and start_time + duration. The amount + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - PoolAsset.token.amount field is ignored if present, future type + Example 2: Pack and unpack a message in Java. - refactorings should just have a type with the denom & weight here. - title: |- - Parameters for changing the weights in a balancer pool smoothly from - a start weight and end weight over a period of time. - Currently, the only smooth change supported is linear changing between - the two weights, but more types may be added in the future. - When these parameters are set, the weight w(t) for pool time `t` is the - following: - t <= start_time: w(t) = initial_pool_weights - start_time < t <= start_time + duration: - w(t) = initial_pool_weights + (t - start_time) * - (target_pool_weights - initial_pool_weights) / (duration) - t > start_time + duration: w(t) = target_pool_weights - osmosis.mint.v1beta1.DistributionProportions: - type: object - properties: - staking: - type: string - description: >- - staking defines the proportion of the minted mint_denom that is to - be + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - allocated as staking rewards. - pool_incentives: - type: string - description: >- - pool_incentives defines the proportion of the minted mint_denom that - is + Example 3: Pack and unpack a message in Python. - to be allocated as pool incentives. - developer_rewards: - type: string - description: >- - developer_rewards defines the proportion of the minted mint_denom - that is + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - to be allocated to developer rewards address. - community_pool: - type: string - description: >- - community_pool defines the proportion of the minted mint_denom that - is + Example 4: Pack and unpack a message in Go - to be allocated to the community pool. - description: >- - DistributionProportions defines the distribution proportions of the - minted + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } - denom. In other words, defines which stakeholders will receive the minted + The pack methods provided by protobuf library will by default use - denoms and how much. - osmosis.mint.v1beta1.Params: - type: object - properties: - mint_denom: - type: string - description: mint_denom is the denom of the coin to mint. - genesis_epoch_provisions: - type: string - description: genesis_epoch_provisions epoch provisions from the first epoch. - epoch_identifier: - type: string - description: epoch_identifier mint epoch identifier e.g. (day, week). - reduction_period_in_epochs: - type: string - format: int64 - description: |- - reduction_period_in_epochs the number of epochs it takes - to reduce the rewards. - reduction_factor: - type: string - description: |- - reduction_factor is the reduction multiplier to execute - at the end of each period set by reduction_period_in_epochs. - distribution_proportions: - description: >- - distribution_proportions defines the distribution proportions of the - minted + 'type.googleapis.com/full.type.name' as the type URL and the unpack - denom. In other words, defines which stakeholders will receive the minted + methods only use the fully qualified type name after the last '/' - denoms and how much. - type: object - properties: - staking: - type: string - description: >- - staking defines the proportion of the minted mint_denom that is - to be + in the type URL, for example "foo.bar.com/x/y.z" will yield type - allocated as staking rewards. - pool_incentives: - type: string - description: >- - pool_incentives defines the proportion of the minted mint_denom - that is + name "y.z". - to be allocated as pool incentives. - developer_rewards: - type: string - description: >- - developer_rewards defines the proportion of the minted - mint_denom that is - to be allocated to developer rewards address. - community_pool: - type: string - description: >- - community_pool defines the proportion of the minted mint_denom - that is - to be allocated to the community pool. - weighted_developer_rewards_receivers: - type: array - items: - type: object - properties: - address: - type: string - weight: - type: string - description: >- - WeightedAddress represents an address with a weight assigned to - it. + JSON - The weight is used to determine the proportion of the total minted - tokens to be minted to the address. - description: >- - weighted_developer_rewards_receivers is the address to receive - developer + The JSON representation of an `Any` value uses the regular - rewards with weights assignedt to each address. The final amount that each + representation of the deserialized, embedded message, with an - address receives is: epoch_provisions * + additional field `@type` which contains the type URL. Example: - distribution_proportions.developer_rewards * Address's Weight. - minting_rewards_distribution_start_epoch: - type: string - format: int64 - title: >- - minting_rewards_distribution_start_epoch start epoch to distribute - minting + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - rewards - description: Params holds parameters for the x/mint module. - osmosis.mint.v1beta1.WeightedAddress: - type: object - properties: - address: - type: string - weight: - type: string - description: |- - WeightedAddress represents an address with a weight assigned to it. - The weight is used to determine the proportion of the total minted - tokens to be minted to the address. - osmosis.poolincentives.v1beta1.DistrInfo: - type: object - properties: - total_weight: - type: string - records: - type: array - items: - type: object - properties: - gauge_id: - type: string - format: uint64 - weight: - type: string - osmosis.poolincentives.v1beta1.DistrRecord: - type: object - properties: - gauge_id: - type: string - format: uint64 - weight: - type: string - osmosis.poolincentives.v1beta1.IncentivizedPool: - type: object - properties: - pool_id: - type: string - format: uint64 - lockable_duration: - type: string - gauge_id: - type: string - format: uint64 - quasarlabs.quasarnode.qoracle.BandchainParams: - type: object - properties: - oracle_ibc_params: - type: object - properties: - authorized_channel: - type: string - timeout_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - RevisionNumber the same. However some consensus algorithms may choose to + If the embedded message type is well-known and has a custom JSON - reset the height in certain conditions e.g. hard forks, state-machine + representation, that representation will be embedded adding a field - breaking changes In these cases, the RevisionNumber is incremented so that + `value` which holds the custom JSON in addition to the `@type` - height continues to be monitonically increasing even as the RevisionHeight + field. Example (for message [google.protobuf.Duration][]): - gets reset - title: >- - Height is a monotonically increasing data type + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + tags: + - Query + "/quasarlabs/quasarnode/qvesting/spendable_balances/{address}": + get: + summary: SpendableBalances queries the spenable balance of all coins for a + single account. + operationId: SpendableBalances + responses: + "200": + description: A successful response. + content: + "*/*": + schema: + type: object + properties: + balances: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - that can be compared against another Height for the purposes of updating and - freezing clients - timeout_timestamp: - type: string - format: uint64 - coin_rates_params: - type: object - properties: - epoch_identifier: - type: string - symbols: - type: array - items: - type: string - script_params: - type: object - properties: - script_id: - type: string - format: uint64 - ask_count: - type: string - format: uint64 - min_count: - type: string - format: uint64 - fee_limit: - type: array - items: + NOTE: The amount field is an Int which implements the custom method + + signatures required by gogoproto. + description: balances is the spendable balances of all the coins. + pagination: + description: pagination defines the pagination in the response. type: object properties: - denom: - type: string - amount: + next_key: type: string - description: >- - Coin defines a token with a denomination and an amount. + format: byte + description: >- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently. It will be empty if - NOTE: The amount field is an Int which implements the custom method + there are no more results. + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total - signatures required by gogoproto. - prepare_gas: - type: string - format: uint64 - execute_gas: - type: string - format: uint64 - quasarlabs.quasarnode.qoracle.CoinRatesParams: - type: object - properties: - epoch_identifier: - type: string - symbols: - type: array - items: - type: string - script_params: - type: object - properties: - script_id: - type: string - format: uint64 - ask_count: - type: string - format: uint64 - min_count: - type: string - format: uint64 - fee_limit: - type: array - items: + was set, its value is undefined otherwise + description: >- + QuerySpendableBalancesResponse defines the gRPC response + structure for querying + + an account's spendable balances. + default: + description: An unexpected error response. + content: + "*/*": + schema: type: object properties: - denom: + error: type: string - amount: + code: + type: integer + format: int32 + message: type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom method + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized - signatures required by gogoproto. - prepare_gas: - type: string - format: uint64 - execute_gas: - type: string - format: uint64 - quasarlabs.quasarnode.qoracle.DenomPriceMapping: - type: object - properties: - denom: - type: string - oracle_denom: - type: string - multiplier: - type: string - quasarlabs.quasarnode.qoracle.IBCParams: - type: object - properties: - authorized_channel: - type: string - timeout_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping + protocol buffer message. This string must contain at least - RevisionNumber the same. However some consensus algorithms may choose to + one "/" character. The last segment of the URL's path must represent - reset the height in certain conditions e.g. hard forks, state-machine + the fully qualified name of the type (as in - breaking changes In these cases, the RevisionNumber is incremented so that + `path/google.protobuf.Duration`). The name should be in a canonical form - height continues to be monitonically increasing even as the RevisionHeight + (e.g., leading "." is not accepted). - gets reset - title: >- - Height is a monotonically increasing data type - that can be compared against another Height for the purposes of updating and + In practice, teams usually precompile into the binary all types that they - freezing clients - timeout_timestamp: - type: string - format: uint64 - quasarlabs.quasarnode.qoracle.OneHopIbcDenomMapping: - type: object - properties: - originName: - type: string - quasar: - type: string - osmo: - type: string - quasarlabs.quasarnode.qoracle.OracleScriptParams: - type: object - properties: - script_id: - type: string - format: uint64 - ask_count: - type: string - format: uint64 - min_count: - type: string - format: uint64 - fee_limit: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + expect it to use in the context of Any. However, for URLs which use the + scheme `http`, `https`, or no scheme, one can optionally set up a type - NOTE: The amount field is an Int which implements the custom method + server that maps type URLs to message definitions as follows: - signatures required by gogoproto. - prepare_gas: - type: string - format: uint64 - execute_gas: - type: string - format: uint64 - quasarlabs.quasarnode.qoracle.OracleScriptState: - type: object - properties: - call_data: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized - protocol buffer message. This string must contain at least + * If no scheme is provided, `https` is assumed. - one "/" character. The last segment of the URL's path must represent + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - the fully qualified name of the type (as in + Note: this functionality is not currently available in the official - `path/google.protobuf.Duration`). The name should be in a canonical form + protobuf release, and it is not used for type URLs beginning with - (e.g., leading "." is not accepted). + type.googleapis.com. - In practice, teams usually precompile into the binary all types that they + Schemes other than `http`, `https` (or the empty scheme) might be - expect it to use in the context of Any. However, for URLs which use the + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a - scheme `http`, `https`, or no scheme, one can optionally set up a type + URL that describes the type of the serialized message. - server that maps type URLs to message definitions as follows: + Protobuf library provides support to pack/unpack Any values in the form - * If no scheme is provided, `https` is assumed. + of utility functions or additional generated methods of the Any type. - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - Note: this functionality is not currently available in the official + Example 1: Pack and unpack a message in C++. - protobuf release, and it is not used for type URLs beginning with + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - type.googleapis.com. + Example 2: Pack and unpack a message in Java. + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - Schemes other than `http`, `https` (or the empty scheme) might be + Example 3: Pack and unpack a message in Python. - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - URL that describes the type of the serialized message. + Example 4: Pack and unpack a message in Go + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } - Protobuf library provides support to pack/unpack Any values in the form + The pack methods provided by protobuf library will by default use - of utility functions or additional generated methods of the Any type. + 'type.googleapis.com/full.type.name' as the type URL and the unpack + methods only use the fully qualified type name after the last '/' - Example 1: Pack and unpack a message in C++. + in the type URL, for example "foo.bar.com/x/y.z" will yield type - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } + name "y.z". - Example 2: Pack and unpack a message in Java. - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - Example 3: Pack and unpack a message in Python. + JSON - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - Example 4: Pack and unpack a message in Go + The JSON representation of an `Any` value uses the regular - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } + representation of the deserialized, embedded message, with an - The pack methods provided by protobuf library will by default use + additional field `@type` which contains the type URL. Example: - 'type.googleapis.com/full.type.name' as the type URL and the unpack + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - methods only use the fully qualified type name after the last '/' + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - in the type URL, for example "foo.bar.com/x/y.z" will yield type + If the embedded message type is well-known and has a custom JSON - name "y.z". + representation, that representation will be embedded adding a field + `value` which holds the custom JSON in addition to the `@type` + field. Example (for message [google.protobuf.Duration][]): - JSON + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: address + description: address is the address to query spendable balances for. + in: path + required: true + schema: + type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + schema: + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + It is less efficient than using key. Only one of offset or key should - The JSON representation of an `Any` value uses the regular + be set. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. - representation of the deserialized, embedded message, with an + If left empty it will default to a value to be set by each app. + in: query + required: false + schema: + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include - additional field `@type` which contains the type URL. Example: + a count of the total number of items available for pagination in UIs. - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + count_total is only respected when offset is used. It is ignored when key - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } + is set. + in: query + required: false + schema: + type: boolean + - name: pagination.reverse + description: >- + reverse is set to true if results are to be returned in the + descending order. - If the embedded message type is well-known and has a custom JSON - representation, that representation will be embedded adding a field + Since: cosmos-sdk 0.43 + in: query + required: false + schema: + type: boolean + tags: + - Query + "/quasarlabs.quasarnode.tokenfactory.v1beta1/denoms/{denom}/authority_metadata": + get: + summary: |- + DenomAuthorityMetadata defines a gRPC query method for fetching + DenomAuthorityMetadata for a particular denom. + operationId: DenomAuthorityMetadata + responses: + "200": + description: A successful response. + content: + "*/*": + schema: + type: object + properties: + authority_metadata: + type: object + properties: + admin: + type: string + title: Can be empty for no admin, or a valid osmosis address + description: >- + DenomAuthorityMetadata specifies metadata for addresses + that have specific - `value` which holds the custom JSON in addition to the `@type` + capabilities over a token factory denom. Right now there is only one Admin - field. Example (for message [google.protobuf.Duration][]): + permission, but is planned to be extended to the future. + description: >- + QueryDenomAuthorityMetadataResponse defines the response + structure for the - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - request_packet_sequence: - type: string - format: uint64 - oracle_request_id: - type: string - format: uint64 - result_packet_sequence: - type: string - format: uint64 - result: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized + DenomAuthorityMetadata gRPC query. + default: + description: An unexpected error response. + content: + "*/*": + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + parameters: + - name: denom + in: path + required: true + schema: + type: string + tags: + - Query + "/quasarlabs.quasarnode.tokenfactory.v1beta1/denoms_from_creator/{creator}": + get: + summary: |- + DenomsFromCreator defines a gRPC query method for fetching all + denominations created by a specific admin/creator. + operationId: DenomsFromCreator + responses: + "200": + description: A successful response. + content: + "*/*": + schema: + type: object + properties: + denoms: + type: array + items: + type: string + description: >- + QueryDenomsFromCreatorRequest defines the response structure + for the - protocol buffer message. This string must contain at least + DenomsFromCreator gRPC query. + default: + description: An unexpected error response. + content: + "*/*": + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + parameters: + - name: creator + in: path + required: true + schema: + type: string + tags: + - Query + /quasarlabs.quasarnode.tokenfactory.v1beta1/params: + get: + summary: >- + Params defines a gRPC query method that returns the tokenfactory + module's - one "/" character. The last segment of the URL's path must represent + parameters. + operationId: TokenfactoryParams + responses: + "200": + description: A successful response. + content: + "*/*": + schema: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + denom_creation_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - the fully qualified name of the type (as in - `path/google.protobuf.Duration`). The name should be in a canonical form + NOTE: The amount field is an Int which implements the custom method - (e.g., leading "." is not accepted). + signatures required by gogoproto. + denom_creation_gas_consume: + type: string + format: uint64 + title: >- + if denom_creation_fee is an empty array, then this + field is used to add more gas consumption + to the base cost. - In practice, teams usually precompile into the binary all types that they + https://github.com/CosmWasm/token-factory/issues/11 + description: QueryParamsResponse is the response type for the Query/Params RPC + method. + default: + description: An unexpected error response. + content: + "*/*": + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + tags: + - Query +components: + schemas: + google.protobuf.Any: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized - expect it to use in the context of Any. However, for URLs which use the + protocol buffer message. This string must contain at least - scheme `http`, `https`, or no scheme, one can optionally set up a type + one "/" character. The last segment of the URL's path must represent - server that maps type URLs to message definitions as follows: + the fully qualified name of the type (as in + `path/google.protobuf.Duration`). The name should be in a canonical form - * If no scheme is provided, `https` is assumed. + (e.g., leading "." is not accepted). - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - Note: this functionality is not currently available in the official + In practice, teams usually precompile into the binary all types that they - protobuf release, and it is not used for type URLs beginning with + expect it to use in the context of Any. However, for URLs which use the - type.googleapis.com. + scheme `http`, `https`, or no scheme, one can optionally set up a type + server that maps type URLs to message definitions as follows: - Schemes other than `http`, `https` (or the empty scheme) might be - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a + * If no scheme is provided, `https` is assumed. - URL that describes the type of the serialized message. + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + Note: this functionality is not currently available in the official - Protobuf library provides support to pack/unpack Any values in the form + protobuf release, and it is not used for type URLs beginning with - of utility functions or additional generated methods of the Any type. + type.googleapis.com. - Example 1: Pack and unpack a message in C++. + Schemes other than `http`, `https` (or the empty scheme) might be - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a - Example 2: Pack and unpack a message in Java. + URL that describes the type of the serialized message. - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - Example 3: Pack and unpack a message in Python. + Protobuf library provides support to pack/unpack Any values in the form - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... + of utility functions or additional generated methods of the Any type. - Example 4: Pack and unpack a message in Go - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } + Example 1: Pack and unpack a message in C++. - The pack methods provided by protobuf library will by default use + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - 'type.googleapis.com/full.type.name' as the type URL and the unpack + Example 2: Pack and unpack a message in Java. - methods only use the fully qualified type name after the last '/' + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - in the type URL, for example "foo.bar.com/x/y.z" will yield type + Example 3: Pack and unpack a message in Python. - name "y.z". + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + Example 4: Pack and unpack a message in Go + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } - JSON + The pack methods provided by protobuf library will by default use + 'type.googleapis.com/full.type.name' as the type URL and the unpack - The JSON representation of an `Any` value uses the regular + methods only use the fully qualified type name after the last '/' - representation of the deserialized, embedded message, with an + in the type URL, for example "foo.bar.com/x/y.z" will yield type - additional field `@type` which contains the type URL. Example: + name "y.z". - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - If the embedded message type is well-known and has a custom JSON + JSON - representation, that representation will be embedded adding a field - `value` which holds the custom JSON in addition to the `@type` + The JSON representation of an `Any` value uses the regular - field. Example (for message [google.protobuf.Duration][]): + representation of the deserialized, embedded message, with an - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - failed: - type: boolean - updated_at_height: - type: string - format: int64 - quasarlabs.quasarnode.qoracle.OsmosisParams: - type: object - properties: - icq_params: - type: object - properties: - authorized_channel: - type: string - timeout_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height while - keeping + additional field `@type` which contains the type URL. Example: - RevisionNumber the same. However some consensus algorithms may choose to + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - reset the height in certain conditions e.g. hard forks, state-machine + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - breaking changes In these cases, the RevisionNumber is incremented so that + If the embedded message type is well-known and has a custom JSON - height continues to be monitonically increasing even as the RevisionHeight + representation, that representation will be embedded adding a field - gets reset - title: >- - Height is a monotonically increasing data type + `value` which holds the custom JSON in addition to the `@type` - that can be compared against another Height for the purposes of updating and + field. Example (for message [google.protobuf.Duration][]): - freezing clients - timeout_timestamp: - type: string - format: uint64 - epoch_identifier: - type: string - quasarlabs.quasarnode.qoracle.OsmosisPool: + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + grpc.gateway.runtime.Error: type: object properties: - pool_info: - type: object - properties: - address: - type: string - id: - type: string - format: uint64 - pool_params: - type: object - properties: - swap_fee: - type: string - exit_fee: - type: string - smooth_weight_change_params: - type: object - properties: - start_time: - type: string - format: date-time - description: >- - The start time for beginning the weight change. - - If a parameter change / pool instantiation leaves this blank, - - it should be generated by the state_machine as the current time. - duration: - type: string - title: Duration for the weights to change over - initial_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, - - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines the - amount of the - - token in the pool, and its balancer weight. - - This is an awkward packaging of data, - - and should be revisited in a future state migration. - description: >- - The initial pool weights. These are copied from the - pool's settings + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized - at the time of weight change instantiation. + protocol buffer message. This string must contain at least - The amount PoolAsset.token.amount field is ignored if present, + one "/" character. The last segment of the URL's path must represent - future type refactorings should just have a type with the denom & weight + the fully qualified name of the type (as in - here. - target_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, + `path/google.protobuf.Duration`). The name should be in a canonical form - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines the - amount of the + (e.g., leading "." is not accepted). - token in the pool, and its balancer weight. - This is an awkward packaging of data, + In practice, teams usually precompile into the binary all types that they - and should be revisited in a future state migration. - description: >- - The target pool weights. The pool weights will change - linearly with respect + expect it to use in the context of Any. However, for URLs which use the - to time between start_time, and start_time + duration. The amount + scheme `http`, `https`, or no scheme, one can optionally set up a type - PoolAsset.token.amount field is ignored if present, future type + server that maps type URLs to message definitions as follows: - refactorings should just have a type with the denom & weight here. - title: >- - Parameters for changing the weights in a balancer pool - smoothly from - a start weight and end weight over a period of time. + * If no scheme is provided, `https` is assumed. - Currently, the only smooth change supported is linear changing between + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - the two weights, but more types may be added in the future. + Note: this functionality is not currently available in the official - When these parameters are set, the weight w(t) for pool time `t` is the + protobuf release, and it is not used for type URLs beginning with - following: - t <= start_time: w(t) = initial_pool_weights - start_time < t <= start_time + duration: - w(t) = initial_pool_weights + (t - start_time) * - (target_pool_weights - initial_pool_weights) / (duration) - t > start_time + duration: w(t) = target_pool_weights - description: >- - PoolParams defined the parameters that will be managed by the - pool + type.googleapis.com. - governance in the future. This params are not managed by the chain - governance. Instead they will be managed by the token holders of the pool. + Schemes other than `http`, `https` (or the empty scheme) might be - The pool's token holders are specified in future_pool_governor. - future_pool_governor: - type: string - title: >- - This string specifies who will govern the pool in the future. + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a - Valid forms of this are: + URL that describes the type of the serialized message. - {token name},{duration} - {duration} + Protobuf library provides support to pack/unpack Any values in the form - where {token name} if specified is the token which determines the + of utility functions or additional generated methods of the Any type. - governor, and if not specified is the LP token for this pool.duration is - a time specified as 0w,1w,2w, etc. which specifies how long the token + Example 1: Pack and unpack a message in C++. - would need to be locked up to count in governance. 0w means no lockup. + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - TODO: Further improve these docs - total_shares: - title: sum of all LP tokens sent out - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + Example 2: Pack and unpack a message in Java. + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - NOTE: The amount field is an Int which implements the custom method + Example 3: Pack and unpack a message in Python. - signatures required by gogoproto. - pool_assets: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines the amount of - the + Example 4: Pack and unpack a message in Go - token in the pool, and its balancer weight. + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } - This is an awkward packaging of data, + The pack methods provided by protobuf library will by default use - and should be revisited in a future state migration. - title: |- - These are assumed to be sorted by denomiation. - They contain the pool asset and the information about the weight - total_weight: - type: string - title: sum of all non-normalized pool weights - metrics: - type: object - properties: - apy: - type: string - format: byte - tvl: - type: string - format: byte - quasarlabs.quasarnode.qoracle.OsmosisPoolMetrics: - type: object - properties: - apy: - type: string - format: byte - tvl: - type: string - format: byte - quasarlabs.quasarnode.qoracle.OsmosisRequestState: - type: object - properties: - packet_sequence: - type: string - format: uint64 - acknowledged: - type: boolean - failed: - type: boolean - updated_at_height: - type: string - format: int64 - quasarlabs.quasarnode.qoracle.Params: - type: object - properties: - bandchain_params: - type: object - properties: - oracle_ibc_params: - type: object - properties: - authorized_channel: - type: string - timeout_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping + 'type.googleapis.com/full.type.name' as the type URL and the unpack - RevisionNumber the same. However some consensus algorithms may choose to + methods only use the fully qualified type name after the last '/' - reset the height in certain conditions e.g. hard forks, state-machine + in the type URL, for example "foo.bar.com/x/y.z" will yield type - breaking changes In these cases, the RevisionNumber is incremented so that + name "y.z". - height continues to be monitonically increasing even as the RevisionHeight - gets reset - title: >- - Height is a monotonically increasing data type - that can be compared against another Height for the purposes of updating and + JSON - freezing clients - timeout_timestamp: - type: string - format: uint64 - coin_rates_params: - type: object - properties: - epoch_identifier: - type: string - symbols: - type: array - items: - type: string - script_params: - type: object - properties: - script_id: - type: string - format: uint64 - ask_count: - type: string - format: uint64 - min_count: - type: string - format: uint64 - fee_limit: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. + The JSON representation of an `Any` value uses the regular - NOTE: The amount field is an Int which implements the custom method + representation of the deserialized, embedded message, with an - signatures required by gogoproto. - prepare_gas: - type: string - format: uint64 - execute_gas: - type: string - format: uint64 - osmosis_params: - type: object - properties: - icq_params: - type: object - properties: - authorized_channel: - type: string - timeout_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping + additional field `@type` which contains the type URL. Example: - RevisionNumber the same. However some consensus algorithms may choose to + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - reset the height in certain conditions e.g. hard forks, state-machine + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - breaking changes In these cases, the RevisionNumber is incremented so that + If the embedded message type is well-known and has a custom JSON - height continues to be monitonically increasing even as the RevisionHeight + representation, that representation will be embedded adding a field - gets reset - title: >- - Height is a monotonically increasing data type + `value` which holds the custom JSON in addition to the `@type` - that can be compared against another Height for the purposes of updating and + field. Example (for message [google.protobuf.Duration][]): - freezing clients - timeout_timestamp: - type: string - format: uint64 - epoch_identifier: - type: string - denom_price_mappings: - type: array - items: - type: object - properties: - denom: - type: string - oracle_denom: - type: string - multiplier: - type: string - oneHopDenomMap: - type: array - items: - type: object - properties: - originName: - type: string - quasar: - type: string - osmo: - type: string - description: Params defines the parameters for the module. - quasarlabs.quasarnode.qoracle.QueryOraclePricesResponse: + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + quasarlabs.quasarnode.epochs.EpochInfo: + type: object + properties: + identifier: + type: string + start_time: + type: string + format: date-time + duration: + type: string + current_epoch: + type: string + format: int64 + current_epoch_start_time: + type: string + format: date-time + epoch_counting_started: + type: boolean + current_epoch_start_height: + type: string + format: int64 + quasarlabs.quasarnode.epochs.QueryCurrentEpochResponse: type: object properties: - prices: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - DecCoin defines a token with a denomination and a decimal amount. - - - NOTE: The amount field is an Dec which implements the custom method - - signatures required by gogoproto. - updated_at_height: + current_epoch: type: string format: int64 - quasarlabs.quasarnode.qoracle.QueryOsmosisChainParamsResponse: + quasarlabs.quasarnode.epochs.QueryEpochsInfoResponse: type: object properties: - epochs_info: + epochs: type: array items: type: object properties: identifier: type: string - description: identifier is a unique reference to this particular timer. start_time: type: string format: date-time - description: >- - start_time is the time at which the timer first ever ticks. - - If start_time is in the future, the epoch will not begin until the start - - time. duration: type: string - description: |- - duration is the time in between epoch ticks. - In order for intended behavior to be met, duration should - be greater than the chains expected block time. - Duration must be non-zero. current_epoch: type: string format: int64 - description: >- - current_epoch is the current epoch number, or in other words, - - how many times has the timer 'ticked'. - - The first tick (current_epoch=1) is defined as - - the first block whose blocktime is greater than the EpochInfo start_time. current_epoch_start_time: type: string format: date-time - description: >- - current_epoch_start_time describes the start time of the - current timer - - interval. The interval is (current_epoch_start_time, - - current_epoch_start_time + duration] When the timer ticks, this is set to - - current_epoch_start_time = last_epoch_start_time + duration only one timer + epoch_counting_started: + type: boolean + current_epoch_start_height: + type: string + format: int64 + cosmos.base.query.v1beta1.PageRequest: + type: object + properties: + key: + type: string + format: byte + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + offset: + type: string + format: uint64 + description: >- + offset is a numeric offset that can be used when key is unavailable. - tick for a given identifier can occur per block. + It is less efficient than using key. Only one of offset or key should + be set. + limit: + type: string + format: uint64 + description: >- + limit is the total number of results to be returned in the result + page. - NOTE! The current_epoch_start_time may diverge significantly from the + If left empty it will default to a value to be set by each app. + count_total: + type: boolean + description: >- + count_total is set to true to indicate that the result set should + include - wall-clock time the epoch began at. Wall-clock time of epoch start may be + a count of the total number of items available for pagination in UIs. - >> current_epoch_start_time. Suppose current_epoch_start_time = 10, + count_total is only respected when offset is used. It is ignored when key - duration = 5. Suppose the chain goes offline at t=14, and comes back online + is set. + reverse: + type: boolean + description: >- + reverse is set to true if results are to be returned in the + descending order. - at t=30, and produces blocks at every successive time. (t=31, 32, etc.) - * The t=30 block will start the epoch for (10, 15] + Since: cosmos-sdk 0.43 + description: |- + message SomeRequest { + Foo some_parameter = 1; + PageRequest pagination = 2; + } + title: |- + PageRequest is to be embedded in gRPC request messages for efficient + pagination. Ex: + cosmos.base.query.v1beta1.PageResponse: + type: object + properties: + next_key: + type: string + format: byte + description: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently. It will be empty if + there are no more results. + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total - * The t=31 block will start the epoch for (15, 20] + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. - * The t=32 block will start the epoch for (20, 25] + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + cosmos.base.v1beta1.Coin: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. - * The t=33 block will start the epoch for (25, 30] + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + quasarlabs.quasarnode.qoracle.Params: + type: object + description: Params defines the parameters for the module. + quasarlabs.quasarnode.qoracle.Pool: + type: object + properties: + id: + type: string + assets: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - * The t=34 block will start the epoch for (30, 35] - * The **t=36** block will start the epoch for (35, 40] - epoch_counting_started: - type: boolean - description: >- - epoch_counting_started is a boolean, that indicates whether - this + NOTE: The amount field is an Int which implements the custom method - epoch timer has began yet. - current_epoch_start_height: - type: string - format: int64 - title: >- - current_epoch_start_height is the block height at which the - current epoch - - started. (The block height at which the timer last ticked) - description: |- - EpochInfo is a struct that describes the data going into - a timer defined by the x/epochs module. - lockable_durations: - type: array - items: - type: string - format: int64 - mint_params: + signatures required by gogoproto. + tvl: + type: string + format: byte + apy: + type: string + format: byte + raw: type: object properties: - mint_denom: - type: string - description: mint_denom is the denom of the coin to mint. - genesis_epoch_provisions: - type: string - description: genesis_epoch_provisions epoch provisions from the first epoch. - epoch_identifier: - type: string - description: epoch_identifier mint epoch identifier e.g. (day, week). - reduction_period_in_epochs: - type: string - format: int64 - description: |- - reduction_period_in_epochs the number of epochs it takes - to reduce the rewards. - reduction_factor: + type_url: type: string - description: |- - reduction_factor is the reduction multiplier to execute - at the end of each period set by reduction_period_in_epochs. - distribution_proportions: description: >- - distribution_proportions defines the distribution proportions of - the minted + A URL/resource name that uniquely identifies the type of the + serialized - denom. In other words, defines which stakeholders will receive the minted + protocol buffer message. This string must contain at least - denoms and how much. - type: object - properties: - staking: - type: string - description: >- - staking defines the proportion of the minted mint_denom that - is to be + one "/" character. The last segment of the URL's path must represent - allocated as staking rewards. - pool_incentives: - type: string - description: >- - pool_incentives defines the proportion of the minted - mint_denom that is + the fully qualified name of the type (as in - to be allocated as pool incentives. - developer_rewards: - type: string - description: >- - developer_rewards defines the proportion of the minted - mint_denom that is + `path/google.protobuf.Duration`). The name should be in a canonical form - to be allocated to developer rewards address. - community_pool: - type: string - description: >- - community_pool defines the proportion of the minted - mint_denom that is + (e.g., leading "." is not accepted). - to be allocated to the community pool. - weighted_developer_rewards_receivers: - type: array - items: - type: object - properties: - address: - type: string - weight: - type: string - description: >- - WeightedAddress represents an address with a weight assigned - to it. - The weight is used to determine the proportion of the total minted + In practice, teams usually precompile into the binary all types that they - tokens to be minted to the address. - description: >- - weighted_developer_rewards_receivers is the address to receive - developer + expect it to use in the context of Any. However, for URLs which use the - rewards with weights assignedt to each address. The final amount that each + scheme `http`, `https`, or no scheme, one can optionally set up a type - address receives is: epoch_provisions * + server that maps type URLs to message definitions as follows: - distribution_proportions.developer_rewards * Address's Weight. - minting_rewards_distribution_start_epoch: - type: string - format: int64 - title: >- - minting_rewards_distribution_start_epoch start epoch to - distribute minting - rewards - description: Params holds parameters for the x/mint module. - mint_epoch_provisions: - type: string - distr_info: - type: object - properties: - total_weight: - type: string - records: - type: array - items: - type: object - properties: - gauge_id: - type: string - format: uint64 - weight: - type: string - quasarlabs.quasarnode.qoracle.QueryOsmosisIncentivizedPoolsResponse: - type: object - properties: - incentivized_pools: - type: array - items: - type: object - properties: - pool_id: - type: string - format: uint64 - lockable_duration: - type: string - gauge_id: - type: string - format: uint64 - quasarlabs.quasarnode.qoracle.QueryOsmosisPoolsResponse: - type: object - properties: - pools: - type: array - items: - type: object - properties: - pool_info: - type: object - properties: - address: - type: string - id: - type: string - format: uint64 - pool_params: - type: object - properties: - swap_fee: - type: string - exit_fee: - type: string - smooth_weight_change_params: - type: object - properties: - start_time: - type: string - format: date-time - description: >- - The start time for beginning the weight change. - - If a parameter change / pool instantiation leaves this blank, - - it should be generated by the state_machine as the current time. - duration: - type: string - title: Duration for the weights to change over - initial_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, - - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines - the amount of the + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - token in the pool, and its balancer weight. + Note: this functionality is not currently available in the official - This is an awkward packaging of data, + protobuf release, and it is not used for type URLs beginning with - and should be revisited in a future state migration. - description: >- - The initial pool weights. These are copied from - the pool's settings - - at the time of weight change instantiation. - - The amount PoolAsset.token.amount field is ignored if present, - - future type refactorings should just have a type with the denom & weight - - here. - target_pool_weights: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, - - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines - the amount of the + type.googleapis.com. - token in the pool, and its balancer weight. - This is an awkward packaging of data, + Schemes other than `http`, `https` (or the empty scheme) might be - and should be revisited in a future state migration. - description: >- - The target pool weights. The pool weights will - change linearly with respect + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the form - to time between start_time, and start_time + duration. The amount + of utility functions or additional generated methods of the Any type. - PoolAsset.token.amount field is ignored if present, future type - refactorings should just have a type with the denom & weight here. - title: >- - Parameters for changing the weights in a balancer pool - smoothly from + Example 1: Pack and unpack a message in C++. - a start weight and end weight over a period of time. + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - Currently, the only smooth change supported is linear changing between + Example 2: Pack and unpack a message in Java. - the two weights, but more types may be added in the future. + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - When these parameters are set, the weight w(t) for pool time `t` is the + Example 3: Pack and unpack a message in Python. - following: - t <= start_time: w(t) = initial_pool_weights - start_time < t <= start_time + duration: - w(t) = initial_pool_weights + (t - start_time) * - (target_pool_weights - initial_pool_weights) / (duration) - t > start_time + duration: w(t) = target_pool_weights - description: >- - PoolParams defined the parameters that will be managed by - the pool + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - governance in the future. This params are not managed by the chain + Example 4: Pack and unpack a message in Go - governance. Instead they will be managed by the token holders of the pool. + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } - The pool's token holders are specified in future_pool_governor. - future_pool_governor: - type: string - title: >- - This string specifies who will govern the pool in the - future. + The pack methods provided by protobuf library will by default use - Valid forms of this are: + 'type.googleapis.com/full.type.name' as the type URL and the unpack - {token name},{duration} + methods only use the fully qualified type name after the last '/' - {duration} + in the type URL, for example "foo.bar.com/x/y.z" will yield type - where {token name} if specified is the token which determines the + name "y.z". - governor, and if not specified is the LP token for this pool.duration is - a time specified as 0w,1w,2w, etc. which specifies how long the token - would need to be locked up to count in governance. 0w means no lockup. + JSON - TODO: Further improve these docs - total_shares: - title: sum of all LP tokens sent out - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + The JSON representation of an `Any` value uses the regular - NOTE: The amount field is an Int which implements the custom method + representation of the deserialized, embedded message, with an - signatures required by gogoproto. - pool_assets: - type: array - items: - type: object - properties: - token: - description: >- - Coins we are talking about, + additional field `@type` which contains the type URL. Example: - the denomination must be unique amongst all PoolAssets for this pool. - type: object - properties: - denom: - type: string - amount: - type: string - weight: - type: string - title: Weight that is not normalized. This weight must be less than 2^50 - description: >- - Pool asset is an internal struct that combines the - amount of the + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - token in the pool, and its balancer weight. + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - This is an awkward packaging of data, + If the embedded message type is well-known and has a custom JSON - and should be revisited in a future state migration. - title: >- - These are assumed to be sorted by denomiation. + representation, that representation will be embedded adding a field - They contain the pool asset and the information about the weight - total_weight: - type: string - title: sum of all non-normalized pool weights - metrics: - type: object - properties: - apy: - type: string - format: byte - tvl: - type: string - format: byte - pagination: - type: object - properties: - next_key: - type: string - format: byte - description: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently. It will be empty if - there are no more results. - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total + `value` which holds the custom JSON in addition to the `@type` - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. + field. Example (for message [google.protobuf.Duration][]): - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + updated_at: + type: string + format: date-time + description: Pool defines the generalized structure of a liquidity pool coming + from any source chain to qoracle. quasarlabs.quasarnode.qoracle.QueryParamsResponse: type: object properties: params: description: params holds all the parameters of this module. type: object - properties: - bandchain_params: - type: object - properties: - oracle_ibc_params: - type: object - properties: - authorized_channel: - type: string - timeout_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each - height while keeping - - RevisionNumber the same. However some consensus algorithms may choose to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so that - - height continues to be monitonically increasing even as the RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes of updating and - - freezing clients - timeout_timestamp: - type: string - format: uint64 - coin_rates_params: + description: QueryParamsResponse is response type for the Query/Params RPC method. + quasarlabs.quasarnode.qoracle.QueryPoolsResponse: + type: object + properties: + pools: + type: array + items: + type: object + properties: + id: + type: string + assets: + type: array + items: type: object properties: - epoch_identifier: + denom: type: string - symbols: - type: array - items: - type: string - script_params: - type: object - properties: - script_id: - type: string - format: uint64 - ask_count: - type: string - format: uint64 - min_count: - type: string - format: uint64 - fee_limit: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an - amount. - - - NOTE: The amount field is an Int which implements the custom method - - signatures required by gogoproto. - prepare_gas: - type: string - format: uint64 - execute_gas: - type: string - format: uint64 - osmosis_params: - type: object - properties: - icq_params: - type: object - properties: - authorized_channel: + amount: type: string - timeout_height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each - height while keeping - - RevisionNumber the same. However some consensus algorithms may choose to - - reset the height in certain conditions e.g. hard forks, state-machine - - breaking changes In these cases, the RevisionNumber is incremented so that - - height continues to be monitonically increasing even as the RevisionHeight + description: >- + Coin defines a token with a denomination and an amount. - gets reset - title: >- - Height is a monotonically increasing data type - that can be compared against another Height for the purposes of updating and + NOTE: The amount field is an Int which implements the custom method - freezing clients - timeout_timestamp: - type: string - format: uint64 - epoch_identifier: - type: string - denom_price_mappings: - type: array - items: - type: object - properties: - denom: - type: string - oracle_denom: - type: string - multiplier: - type: string - oneHopDenomMap: - type: array - items: + signatures required by gogoproto. + tvl: + type: string + format: byte + apy: + type: string + format: byte + raw: type: object properties: - originName: - type: string - quasar: - type: string - osmo: + type_url: type: string - description: QueryParamsResponse is response type for the Query/Params RPC method. - quasarlabs.quasarnode.qoracle.QueryStateResponse: - type: object - properties: - coin_rates_state: - type: object - properties: - call_data: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized + description: >- + A URL/resource name that uniquely identifies the type of + the serialized - protocol buffer message. This string must contain at least + protocol buffer message. This string must contain at least - one "/" character. The last segment of the URL's path must represent + one "/" character. The last segment of the URL's path must represent - the fully qualified name of the type (as in + the fully qualified name of the type (as in - `path/google.protobuf.Duration`). The name should be in a canonical form + `path/google.protobuf.Duration`). The name should be in a canonical form - (e.g., leading "." is not accepted). + (e.g., leading "." is not accepted). - In practice, teams usually precompile into the binary all types that they + In practice, teams usually precompile into the binary all types that they - expect it to use in the context of Any. However, for URLs which use the + expect it to use in the context of Any. However, for URLs which use the - scheme `http`, `https`, or no scheme, one can optionally set up a type + scheme `http`, `https`, or no scheme, one can optionally set up a type - server that maps type URLs to message definitions as follows: + server that maps type URLs to message definitions as follows: - * If no scheme is provided, `https` is assumed. + * If no scheme is provided, `https` is assumed. - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - Note: this functionality is not currently available in the official + Note: this functionality is not currently available in the official - protobuf release, and it is not used for type URLs beginning with + protobuf release, and it is not used for type URLs beginning with - type.googleapis.com. + type.googleapis.com. - Schemes other than `http`, `https` (or the empty scheme) might be + Schemes other than `http`, `https` (or the empty scheme) might be - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a - URL that describes the type of the serialized message. + URL that describes the type of the serialized message. - Protobuf library provides support to pack/unpack Any values in the form + Protobuf library provides support to pack/unpack Any values in the form - of utility functions or additional generated methods of the Any type. + of utility functions or additional generated methods of the Any type. - Example 1: Pack and unpack a message in C++. + Example 1: Pack and unpack a message in C++. - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { + Foo foo = ...; + Any any; + any.PackFrom(foo); ... - } + if (any.UnpackTo(&foo)) { + ... + } - Example 2: Pack and unpack a message in Java. + Example 2: Pack and unpack a message in Java. - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - Example 3: Pack and unpack a message in Python. + Example 3: Pack and unpack a message in Python. - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) + foo = Foo(...) + any = Any() + any.Pack(foo) ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - Example 4: Pack and unpack a message in Go + Example 4: Pack and unpack a message in Go - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } - ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { + ... + } ... - } + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use - The pack methods provided by protobuf library will by default use + 'type.googleapis.com/full.type.name' as the type URL and the unpack - 'type.googleapis.com/full.type.name' as the type URL and the unpack + methods only use the fully qualified type name after the last '/' - methods only use the fully qualified type name after the last '/' + in the type URL, for example "foo.bar.com/x/y.z" will yield type - in the type URL, for example "foo.bar.com/x/y.z" will yield type + name "y.z". - name "y.z". + JSON - JSON + The JSON representation of an `Any` value uses the regular - The JSON representation of an `Any` value uses the regular + representation of the deserialized, embedded message, with an - representation of the deserialized, embedded message, with an + additional field `@type` which contains the type URL. Example: - additional field `@type` which contains the type URL. Example: + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } + If the embedded message type is well-known and has a custom JSON - If the embedded message type is well-known and has a custom JSON + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + updated_at: + type: string + format: date-time + description: Pool defines the generalized structure of a liquidity pool coming + from any source chain to qoracle. + pagination: + description: pagination defines the pagination in the response. + type: object + properties: + next_key: + type: string + format: byte + description: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently. It will be empty if + there are no more results. + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total - representation, that representation will be embedded adding a field + was set, its value is undefined otherwise + description: QueryPoolsResponse is response type for the Query/Pools RPC method. + quasarlabs.quasarnode.qvesting.Params: + type: object + description: Params defines the parameters for the module. + quasarlabs.quasarnode.qvesting.QueryParamsResponse: + type: object + properties: + params: + description: params holds all the parameters of this module. + type: object + description: QueryParamsResponse is response type for the Query/Params RPC method. + quasarlabs.quasarnode.qvesting.QuerySpendableBalancesResponse: + type: object + properties: + balances: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - `value` which holds the custom JSON in addition to the `@type` - field. Example (for message [google.protobuf.Duration][]): + NOTE: The amount field is an Int which implements the custom method - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - request_packet_sequence: - type: string - format: uint64 - oracle_request_id: + signatures required by gogoproto. + description: balances is the spendable balances of all the coins. + pagination: + description: pagination defines the pagination in the response. + type: object + properties: + next_key: type: string - format: uint64 - result_packet_sequence: + format: byte + description: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently. It will be empty if + there are no more results. + total: type: string format: uint64 - result: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized + title: >- + total is total number of results available if + PageRequest.count_total - protocol buffer message. This string must contain at least + was set, its value is undefined otherwise + description: >- + QuerySpendableBalancesResponse defines the gRPC response structure for + querying + + an account's spendable balances. + quasarlabs.quasarnode.qvesting.QueryVestingAccountsResponse: + type: object + properties: + accounts: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized - one "/" character. The last segment of the URL's path must represent + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must represent - the fully qualified name of the type (as in + the fully qualified name of the type (as in - `path/google.protobuf.Duration`). The name should be in a canonical form + `path/google.protobuf.Duration`). The name should be in a canonical form - (e.g., leading "." is not accepted). + (e.g., leading "." is not accepted). - In practice, teams usually precompile into the binary all types that they + In practice, teams usually precompile into the binary all types that they - expect it to use in the context of Any. However, for URLs which use the + expect it to use in the context of Any. However, for URLs which use the - scheme `http`, `https`, or no scheme, one can optionally set up a type + scheme `http`, `https`, or no scheme, one can optionally set up a type - server that maps type URLs to message definitions as follows: + server that maps type URLs to message definitions as follows: - * If no scheme is provided, `https` is assumed. + * If no scheme is provided, `https` is assumed. - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - Note: this functionality is not currently available in the official + Note: this functionality is not currently available in the official - protobuf release, and it is not used for type URLs beginning with + protobuf release, and it is not used for type URLs beginning with - type.googleapis.com. + type.googleapis.com. - Schemes other than `http`, `https` (or the empty scheme) might be + Schemes other than `http`, `https` (or the empty scheme) might be - used with implementation specific semantics. - value: - type: string - format: byte - description: Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a + used with implementation specific semantics. + value: + type: string + format: byte + description: Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a - URL that describes the type of the serialized message. + URL that describes the type of the serialized message. - Protobuf library provides support to pack/unpack Any values in the form + Protobuf library provides support to pack/unpack Any values in the form - of utility functions or additional generated methods of the Any type. + of utility functions or additional generated methods of the Any type. - Example 1: Pack and unpack a message in C++. + Example 1: Pack and unpack a message in C++. - Foo foo = ...; - Any any; - any.PackFrom(foo); + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { ... - if (any.UnpackTo(&foo)) { - ... - } + } - Example 2: Pack and unpack a message in Java. + Example 2: Pack and unpack a message in Java. - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - Example 3: Pack and unpack a message in Python. + Example 3: Pack and unpack a message in Python. - foo = Foo(...) - any = Any() - any.Pack(foo) + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - Example 4: Pack and unpack a message in Go + Example 4: Pack and unpack a message in Go - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } + foo := &pb.Foo{...} + any, err := anypb.New(foo) + if err != nil { ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } + } + ... + foo := &pb.Foo{} + if err := any.UnmarshalTo(foo); err != nil { + ... + } - The pack methods provided by protobuf library will by default use + The pack methods provided by protobuf library will by default use - 'type.googleapis.com/full.type.name' as the type URL and the unpack + 'type.googleapis.com/full.type.name' as the type URL and the unpack - methods only use the fully qualified type name after the last '/' + methods only use the fully qualified type name after the last '/' - in the type URL, for example "foo.bar.com/x/y.z" will yield type + in the type URL, for example "foo.bar.com/x/y.z" will yield type - name "y.z". + name "y.z". - JSON + JSON - The JSON representation of an `Any` value uses the regular + The JSON representation of an `Any` value uses the regular - representation of the deserialized, embedded message, with an + representation of the deserialized, embedded message, with an - additional field `@type` which contains the type URL. Example: + additional field `@type` which contains the type URL. Example: - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - If the embedded message type is well-known and has a custom JSON + If the embedded message type is well-known and has a custom JSON - representation, that representation will be embedded adding a field + representation, that representation will be embedded adding a field - `value` which holds the custom JSON in addition to the `@type` + `value` which holds the custom JSON in addition to the `@type` - field. Example (for message [google.protobuf.Duration][]): + field. Example (for message [google.protobuf.Duration][]): - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - failed: - type: boolean - updated_at_height: - type: string - format: int64 - osmosis_params_request_state: + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: accounts are the existing vesting accounts + pagination: + description: pagination defines the pagination in the response. type: object properties: - packet_sequence: - type: string - format: uint64 - acknowledged: - type: boolean - failed: - type: boolean - updated_at_height: + next_key: type: string - format: int64 - osmosis_incentivized_pools_state: - type: object - properties: - packet_sequence: + format: byte + description: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently. It will be empty if + there are no more results. + total: type: string format: uint64 - acknowledged: - type: boolean - failed: - type: boolean - updated_at_height: - type: string - format: int64 - osmosis_pools_state: + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: QueryVestingAccountsResponse is the response type for the + Query/Accounts RPC method. + quasarlabs.quasarnode.qvesting.QueryVestingLockedSupplyResponse: + type: object + properties: + amount: + description: amount is the supply of the coin. type: object properties: - packet_sequence: + denom: type: string - format: uint64 - acknowledged: - type: boolean - failed: - type: boolean - updated_at_height: + amount: type: string - format: int64 - quasarlabs.quasarnode.qvesting.MsgCreateVestingAccountResponse: - type: object - quasarlabs.quasarnode.qvesting.Params: - type: object - description: Params defines the parameters for the module. - quasarlabs.quasarnode.qvesting.QueryParamsResponse: + description: QueryVestingAccountsResponse is the response type for the + Query/VestingLockedSupply RPC method. + quasarlabs.quasarnode.tokenfactory.v1beta1.DenomAuthorityMetadata: type: object properties: - params: - description: params holds all the parameters of this module. - type: object - description: QueryParamsResponse is response type for the Query/Params RPC method. - quasarlabs.quasarnode.qvesting.QuerySpendableBalancesResponse: + admin: + type: string + title: Can be empty for no admin, or a valid osmosis address + description: >- + DenomAuthorityMetadata specifies metadata for addresses that have + specific + + capabilities over a token factory denom. Right now there is only one Admin + + permission, but is planned to be extended to the future. + quasarlabs.quasarnode.tokenfactory.v1beta1.Params: type: object properties: - balances: + denom_creation_fee: type: array - description: balances is the spendable balances of all the coins. - pagination: - description: pagination defines the pagination in the response. - description: QuerySpendableBalancesResponse defines the gRPC response structure for querying\nan account's spendable balances. - quasarlabs.quasarnode.qvesting.QueryVestingAccountsResponse: + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. + + + NOTE: The amount field is an Int which implements the custom method + + signatures required by gogoproto. + denom_creation_gas_consume: + type: string + format: uint64 + title: >- + if denom_creation_fee is an empty array, then this field is used to + add more gas consumption + + to the base cost. + + https://github.com/CosmWasm/token-factory/issues/11 + description: Params defines the parameters for the tokenfactory module. + quasarlabs.quasarnode.tokenfactory.v1beta1.QueryDenomAuthorityMetadataResponse: type: object properties: - accounts: + authority_metadata: + type: object + properties: + admin: + type: string + title: Can be empty for no admin, or a valid osmosis address + description: >- + DenomAuthorityMetadata specifies metadata for addresses that have + specific + + capabilities over a token factory denom. Right now there is only one Admin + + permission, but is planned to be extended to the future. + description: >- + QueryDenomAuthorityMetadataResponse defines the response structure for + the + + DenomAuthorityMetadata gRPC query. + quasarlabs.quasarnode.tokenfactory.v1beta1.QueryDenomsFromCreatorResponse: + type: object + properties: + denoms: type: array - title: accounts are the existing vesting accounts - pagination: - description: pagination defines the pagination in the response. - description: QueryVestingAccountsResponse is the response type for the Query/Accounts RPC method. - quasarlabs.quasarnode.qvesting.QueryVestingLockedSupplyResponse: + items: + type: string + description: |- + QueryDenomsFromCreatorRequest defines the response structure for the + DenomsFromCreator gRPC query. + quasarlabs.quasarnode.tokenfactory.v1beta1.QueryParamsResponse: type: object properties: - denom: - type: string - amount: - type: string - description: QueryVestingLockedSupplyResponse is the response type for the Query/AccountsLockedSupply RPC method. + params: + description: params defines the parameters of the module. + type: object + properties: + denom_creation_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. + + + NOTE: The amount field is an Int which implements the custom method + + signatures required by gogoproto. + denom_creation_gas_consume: + type: string + format: uint64 + title: >- + if denom_creation_fee is an empty array, then this field is used + to add more gas consumption + + to the base cost. + https://github.com/CosmWasm/token-factory/issues/11 + description: QueryParamsResponse is the response type for the Query/Params RPC method. diff --git a/docs/swagger-combine.config.json b/docs/swagger-combine.config.json index dcbe6cb5a..a8e2bc5af 100644 --- a/docs/swagger-combine.config.json +++ b/docs/swagger-combine.config.json @@ -15,34 +15,26 @@ } }, { - "url": "../tmp-swagger-gen/intergamm/query.swagger.json", - "operationIds": { - "rename": { - "Params": "IntergammParams" - } - } - }, - { - "url": "../tmp-swagger-gen/orion/query.swagger.json", + "url": "../tmp-swagger-gen/qoracle/query.swagger.json", "operationIds": { "rename": { - "Params": "OrionParams" + "Params": "QOracleParams" } } }, { - "url": "../tmp-swagger-gen/qbank/query.swagger.json", + "url": "../tmp-swagger-gen/qvesting/query.swagger.json", "operationIds": { "rename": { - "Params": "QBankParams" + "Params": "QVestingParams" } } }, { - "url": "../tmp-swagger-gen/qoracle/query.swagger.json", + "url": "../tmp-swagger-gen/tokenfactory/v1beta1/query.swagger.json", "operationIds": { "rename": { - "Params": "QOracleParams" + "Params": "TokenfactoryParams" } } } diff --git a/docs/yarn.lock b/docs/yarn.lock index 7664c742f..70fdef67e 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -2,9 +2,9 @@ # yarn lockfile v1 -"@apidevtools/json-schema-ref-parser@9.0.9", "@apidevtools/json-schema-ref-parser@^9.0.6": +"@apidevtools/json-schema-ref-parser@^9.0.6", "@apidevtools/json-schema-ref-parser@9.0.9": version "9.0.9" - resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#d720f9256e3609621280584f2b47ae165359268b" + resolved "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz" integrity sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w== dependencies: "@jsdevtools/ono" "^7.1.3" @@ -14,17 +14,17 @@ "@apidevtools/openapi-schemas@^2.0.4": version "2.1.0" - resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" + resolved "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz" integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== "@apidevtools/swagger-methods@^3.0.2": version "3.0.2" - resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" + resolved "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz" integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== "@apidevtools/swagger-parser@10.0.3": version "10.0.3" - resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz#32057ae99487872c4dd96b314a1ab4b95d89eaf5" + resolved "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz" integrity sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g== dependencies: "@apidevtools/json-schema-ref-parser" "^9.0.6" @@ -36,44 +36,58 @@ "@exodus/schemasafe@^1.0.0-rc.2": version "1.0.0-rc.7" - resolved "https://registry.yarnpkg.com/@exodus/schemasafe/-/schemasafe-1.0.0-rc.7.tgz#aded6839c2369883dafa46608a135c82b42ed76b" + resolved "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.0.0-rc.7.tgz" integrity sha512-+1mBLsa+vvlV0lwEAP1hwgmOPkjMnoJ8hyCMfCCJga0sVDwDzrPJjnxZwdDaUmOh/vbFHQGBTk+FxsVjoI/CjQ== "@jsdevtools/ono@^7.1.3": version "7.1.3" - resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" + resolved "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== "@types/json-schema@^7.0.6": version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^4.0.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" argparse@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== call-me-maybe@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + resolved "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz" integrity sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw== +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + cliui@^7.0.2: version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" @@ -82,130 +96,150 @@ cliui@^7.0.2: color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== commander@^2.20.3: version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== es6-promise@^3.2.1: version "3.3.1" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz" integrity sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg== escalade@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== fast-safe-stringify@^2.0.7: version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + resolved "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== -get-caller-file@^2.0.5: +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== http2-client@^1.2.5: version "1.3.5" - resolved "https://registry.yarnpkg.com/http2-client/-/http2-client-1.3.5.tgz#20c9dc909e3cc98284dd20af2432c524086df181" + resolved "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz" integrity sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA== is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== js-yaml@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" json-schema-ref-parser@^9.0.9: version "9.0.9" - resolved "https://registry.yarnpkg.com/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#66ea538e7450b12af342fa3d5b8458bc1e1e013f" + resolved "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz" integrity sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q== dependencies: "@apidevtools/json-schema-ref-parser" "9.0.9" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + lodash.get@^4.4.2: version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== lodash.isequal@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== lodash@^4.17.21: version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== minimist@^1.2.5: version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== node-fetch-h2@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz#c6188325f9bd3d834020bf0f2d6dc17ced2241ac" + resolved "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz" integrity sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg== dependencies: http2-client "^1.2.5" node-fetch@^2.6.1: version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" node-readfiles@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/node-readfiles/-/node-readfiles-0.2.0.tgz#dbbd4af12134e2e635c245ef93ffcf6f60673a5d" + resolved "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz" integrity sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA== dependencies: es6-promise "^3.2.1" oas-kit-common@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/oas-kit-common/-/oas-kit-common-1.0.8.tgz#6d8cacf6e9097967a4c7ea8bcbcbd77018e1f535" + resolved "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz" integrity sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ== dependencies: fast-safe-stringify "^2.0.7" oas-linter@^3.2.2: version "3.2.2" - resolved "https://registry.yarnpkg.com/oas-linter/-/oas-linter-3.2.2.tgz#ab6a33736313490659035ca6802dc4b35d48aa1e" + resolved "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz" integrity sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ== dependencies: "@exodus/schemasafe" "^1.0.0-rc.2" should "^13.2.1" yaml "^1.10.0" -oas-resolver@^2.5.6: +oas-resolver@^2.5.2, oas-resolver@^2.5.6: version "2.5.6" - resolved "https://registry.yarnpkg.com/oas-resolver/-/oas-resolver-2.5.6.tgz#10430569cb7daca56115c915e611ebc5515c561b" + resolved "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz" integrity sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ== dependencies: node-fetch-h2 "^2.3.0" @@ -216,12 +250,12 @@ oas-resolver@^2.5.6: oas-schema-walker@^1.1.5: version "1.1.5" - resolved "https://registry.yarnpkg.com/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz#74c3cd47b70ff8e0b19adada14455b5d3ac38a22" + resolved "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz" integrity sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ== -oas-validator@^5.0.8: +oas-validator@^5.0.3: version "5.0.8" - resolved "https://registry.yarnpkg.com/oas-validator/-/oas-validator-5.0.8.tgz#387e90df7cafa2d3ffc83b5fb976052b87e73c28" + resolved "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz" integrity sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw== dependencies: call-me-maybe "^1.0.1" @@ -233,26 +267,65 @@ oas-validator@^5.0.8: should "^13.2.1" yaml "^1.10.0" -reftools@^1.1.9: +openapi-types@>=7: + version "12.1.3" + resolved "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz" + integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +reftools@^1.1.6, reftools@^1.1.9: version "1.1.9" - resolved "https://registry.yarnpkg.com/reftools/-/reftools-1.1.9.tgz#e16e19f662ccd4648605312c06d34e5da3a2b77e" + resolved "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz" integrity sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w== require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + should-equal@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" + resolved "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz" integrity sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA== dependencies: should-type "^1.4.0" should-format@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/should-format/-/should-format-3.0.3.tgz#9bfc8f74fa39205c53d38c34d717303e277124f1" + resolved "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz" integrity sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q== dependencies: should-type "^1.3.0" @@ -260,7 +333,7 @@ should-format@^3.0.3: should-type-adaptors@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz#401e7f33b5533033944d5cd8bf2b65027792e27a" + resolved "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz" integrity sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA== dependencies: should-type "^1.3.0" @@ -268,17 +341,17 @@ should-type-adaptors@^1.0.1: should-type@^1.3.0, should-type@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/should-type/-/should-type-1.4.0.tgz#0756d8ce846dfd09843a6947719dfa0d4cff5cf3" + resolved "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz" integrity sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ== should-util@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/should-util/-/should-util-1.0.1.tgz#fb0d71338f532a3a149213639e2d32cbea8bcb28" + resolved "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz" integrity sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g== should@^13.2.1: version "13.2.3" - resolved "https://registry.yarnpkg.com/should/-/should-13.2.3.tgz#96d8e5acf3e97b49d89b51feaa5ae8d07ef58f10" + resolved "https://registry.npmjs.org/should/-/should-13.2.3.tgz" integrity sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ== dependencies: should-equal "^2.0.0" @@ -289,7 +362,7 @@ should@^13.2.1: string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -298,14 +371,14 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" swagger-combine@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/swagger-combine/-/swagger-combine-1.4.0.tgz#f66ccc5fe26ff3a3fb22d986d598dfcc0e0bc956" + resolved "https://registry.npmjs.org/swagger-combine/-/swagger-combine-1.4.0.tgz" integrity sha512-nVQPzSGixSJ6U3BSTBYswIbamumNCz1ZXPqnCrXYz6BHlSeOtfGKuyZ+sAWtpOepUFuOu93x+VOIzAxLKK6xYw== dependencies: call-me-maybe "^1.0.1" @@ -319,88 +392,132 @@ swagger-combine@^1.4.0: swagger-parser@^10.0.3: version "10.0.3" - resolved "https://registry.yarnpkg.com/swagger-parser/-/swagger-parser-10.0.3.tgz#04cb01c18c3ac192b41161c77f81e79309135d03" + resolved "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz" integrity sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg== dependencies: "@apidevtools/swagger-parser" "10.0.3" swagger2openapi@^7.0.3: - version "7.0.8" - resolved "https://registry.yarnpkg.com/swagger2openapi/-/swagger2openapi-7.0.8.tgz#12c88d5de776cb1cbba758994930f40ad0afac59" - integrity sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g== + version "7.0.3" + resolved "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.3.tgz" + integrity sha512-JSFUmXSR7Qx9WwSKCEqaL4oQfhLLCU2r8Zgf30g15FdSkihItZ6fKFnqSsfqQ6MsmnLlcBf8+OhnQHbi1R0ydg== dependencies: call-me-maybe "^1.0.1" node-fetch "^2.6.1" node-fetch-h2 "^2.3.0" node-readfiles "^0.2.0" oas-kit-common "^1.0.8" - oas-resolver "^2.5.6" + oas-resolver "^2.5.2" oas-schema-walker "^1.1.5" - oas-validator "^5.0.8" - reftools "^1.1.9" + oas-validator "^5.0.3" + reftools "^1.1.6" yaml "^1.10.0" - yargs "^17.0.1" + yargs "^15.3.1" tr46@~0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== traverse@^0.6.6: version "0.6.6" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" + resolved "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz" integrity sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw== url-join@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" + resolved "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz" integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== validator@^13.7.0: version "13.7.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857" + resolved "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz" integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== webidl-conversions@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== whatwg-url@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" string-width "^4.1.0" strip-ansi "^6.0.0" +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + y18n@^5.0.5: version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== yaml@^1.10.0: version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^21.0.0: version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== +yargs@^15.3.1: + version "15.4.1" + resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + yargs@^17.0.1: version "17.5.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz" integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== dependencies: cliui "^7.0.2" @@ -413,7 +530,7 @@ yargs@^17.0.1: z-schema@^5.0.1: version "5.0.4" - resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.4.tgz#ecad8bc5ef3283ae032d603286386cfb1380cce5" + resolved "https://registry.npmjs.org/z-schema/-/z-schema-5.0.4.tgz" integrity sha512-gm/lx3hDzJNcLwseIeQVm1UcwhWIKpSB4NqH89pTBtFns4k/HDHudsICtvG05Bvw/Mv3jMyk700y5dadueLHdA== dependencies: lodash.get "^4.4.2" diff --git a/scripts/generate-docs.sh b/scripts/generate-docs.sh index ac1da186d..41d3c3937 100755 --- a/scripts/generate-docs.sh +++ b/scripts/generate-docs.sh @@ -1,27 +1,43 @@ -#!/usr/bin/env bash +#!/usr/bin/bash +echo "Starting to generate api docs" set -Cue -o pipefail project_dir="$(cd "$(dirname "${0}")/.." ; pwd)" # Absolute path to project dir +echo "Project dir : ${project_dir}" docs_dir="${project_dir}/docs" +echo "docs_dir : ${docs_dir}" + tmp_dir="${project_dir}/tmp-swagger-gen" +echo "tmp_dir : ${tmp_dir}" mkdir -p $tmp_dir trap "rm -rf ${tmp_dir}" 0 proto_dirs=$(find ${project_dir}/proto -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) +echo "proto_dirs : ${proto_dirs}" + +echo "================================================" for dir in $proto_dirs; do # generate swagger files (filter query files) + echo "inside loop - dir : ${dir}" + query_file=$(find "${dir}" -maxdepth 1 \( -name 'query.proto' -o -name 'service.proto' \)) + echo "query file : ${query_file}" if [[ ! -z "$query_file" ]]; then + echo "generate file for query file : ${query_file}" buf generate --template "${project_dir}/proto/buf.gen.swagger.yaml" $query_file fi done ( cd "$docs_dir" - - yarn install - yarn combine - yarn convert + # NOTE - You might need to run the below commands in your local + # in case they are not properly installed. Yarn sometimes does not work + # on some systems + npm run combine + npm run convert + # yarn install + # yarn combine + # yarn convert ) From d53c044c285f8493e691dab77db9dab02acd55f3 Mon Sep 17 00:00:00 2001 From: Arham Chordia <43543921+arhamchordia@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:40:22 +0530 Subject: [PATCH 3/7] Reverting wasmvm version to v1.2.1 and bumping ibc-go to v4.4.2 --- go.mod | 4 ++-- go.sum | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c21116427..e7705e330 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/CosmWasm/wasmd v0.31.0 github.com/cosmos/cosmos-sdk v0.45.16 - github.com/cosmos/ibc-go/v4 v4.3.0 + github.com/cosmos/ibc-go/v4 v4.4.2 github.com/gogo/protobuf v1.3.3 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 @@ -29,7 +29,7 @@ require ( ) require ( - github.com/CosmWasm/wasmvm v1.2.3 + github.com/CosmWasm/wasmvm v1.2.1 github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/gogoproto v1.4.6 github.com/strangelove-ventures/async-icq/v4 v4.0.0-rc0 diff --git a/go.sum b/go.sum index 5148d78d3..324eabccd 100644 --- a/go.sum +++ b/go.sum @@ -78,6 +78,8 @@ github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mo github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/CosmWasm/wasmd v0.31.0 h1:xACf6A/SkCeGWQWrKGsR4X9PQb5G4XYuNfnrl+HQ1mE= github.com/CosmWasm/wasmd v0.31.0/go.mod h1:VcyDGk/ISVlMUeW+1GGL0zdHWBS2FPwLEV2qZ86l7l8= +github.com/CosmWasm/wasmvm v1.2.1 h1:si0tRsRDdUShV0k51Wn6zRKlmj3/WWP9Yr4cLmDTf+8= +github.com/CosmWasm/wasmvm v1.2.1/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8J7KFtkc= github.com/CosmWasm/wasmvm v1.2.3 h1:OKYlobwmVGbl0eSn0mXoAAjE5hIuXnQCLPjbNd91sVY= github.com/CosmWasm/wasmvm v1.2.3/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8J7KFtkc= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -158,6 +160,7 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxq github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -262,6 +265,7 @@ github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvA github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -286,6 +290,8 @@ github.com/cosmos/iavl v0.19.5 h1:rGA3hOrgNxgRM5wYcSCxgQBap7fW82WZgY78V9po/iY= github.com/cosmos/iavl v0.19.5/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/ibc-go/v4 v4.3.0 h1:yOzVsyZzsv4XPBux8gq+D0LhZn45yGWKjvT+6Vyo5no= github.com/cosmos/ibc-go/v4 v4.3.0/go.mod h1:CcLvIoi9NNtIbNsxs4KjBGjYhlwqtsmXy1AKARKiMzQ= +github.com/cosmos/ibc-go/v4 v4.4.2 h1:PG4Yy0/bw6Hvmha3RZbc53KYzaCwuB07Ot4GLyzcBvo= +github.com/cosmos/ibc-go/v4 v4.4.2/go.mod h1:j/kD2JCIaV5ozvJvaEkWhLxM2zva7/KTM++EtKFYcB8= github.com/cosmos/interchain-accounts v0.2.6 h1:TV2M2g1/Rb9MCNw1YePdBKE0rcEczNj1RGHT+2iRYas= github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKyF3nNqAXZA= github.com/cosmos/ledger-cosmos-go v0.12.2/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B74i+2/8MhZw4ziiI= @@ -501,6 +507,7 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= @@ -656,6 +663,7 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -665,6 +673,7 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -775,6 +784,7 @@ github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2 github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= +github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.6.2 h1:uGQ9xI8/pgc9iOoCe7kWQgRE6SBTrCGmTSf0LrEtY7c= github.com/kisielk/errcheck v1.6.2/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= @@ -1325,6 +1335,7 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1332,6 +1343,7 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= From 62bcb09f94b1f84b6eb3e5ed868768fb1f7545bc Mon Sep 17 00:00:00 2001 From: Arham Chordia <43543921+arhamchordia@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:40:52 +0530 Subject: [PATCH 4/7] Adding a software upgrade shell test with contracts. --- demos/orion-manual-demo/run_all.sh | 4 +- demos/upgrade-handler/v1.0.0/README.md | 64 ++++- .../go-relayer-config/chains/osmosis.json | 16 ++ .../go-relayer-config/chains/quasar.json | 16 ++ .../paths/quasar_osmosis.json | 12 + .../v1.0.0/go_relayer_setup.sh | 24 ++ demos/upgrade-handler/v1.0.0/keys/gaia.key | 1 + demos/upgrade-handler/v1.0.0/keys/osmo.key | 1 + demos/upgrade-handler/v1.0.0/keys/qsr.key | 1 + demos/upgrade-handler/v1.0.0/osmo_localnet.sh | 255 ++++++++++++++++++ .../v1.0.0/pools/sample_pool1.json | 7 + .../v1.0.0/pools/sample_pool2.json | 7 + .../v1.0.0/pools/sample_pool3.json | 7 + demos/upgrade-handler/v1.0.0/post_upgrade.sh | 41 +++ demos/upgrade-handler/v1.0.0/pre_upgrade.sh | 110 ++++++++ .../upgrade-handler/v1.0.0/quasar_localnet.sh | 126 +++++++++ demos/upgrade-handler/v1.0.0/upgrade.sh | 52 ++++ 17 files changed, 741 insertions(+), 3 deletions(-) create mode 100644 demos/upgrade-handler/v1.0.0/go-relayer-config/chains/osmosis.json create mode 100644 demos/upgrade-handler/v1.0.0/go-relayer-config/chains/quasar.json create mode 100644 demos/upgrade-handler/v1.0.0/go-relayer-config/paths/quasar_osmosis.json create mode 100755 demos/upgrade-handler/v1.0.0/go_relayer_setup.sh create mode 100644 demos/upgrade-handler/v1.0.0/keys/gaia.key create mode 100644 demos/upgrade-handler/v1.0.0/keys/osmo.key create mode 100644 demos/upgrade-handler/v1.0.0/keys/qsr.key create mode 100755 demos/upgrade-handler/v1.0.0/osmo_localnet.sh create mode 100644 demos/upgrade-handler/v1.0.0/pools/sample_pool1.json create mode 100644 demos/upgrade-handler/v1.0.0/pools/sample_pool2.json create mode 100644 demos/upgrade-handler/v1.0.0/pools/sample_pool3.json create mode 100755 demos/upgrade-handler/v1.0.0/post_upgrade.sh create mode 100755 demos/upgrade-handler/v1.0.0/pre_upgrade.sh create mode 100755 demos/upgrade-handler/v1.0.0/quasar_localnet.sh create mode 100755 demos/upgrade-handler/v1.0.0/upgrade.sh diff --git a/demos/orion-manual-demo/run_all.sh b/demos/orion-manual-demo/run_all.sh index b2fb1c99f..7d962a327 100755 --- a/demos/orion-manual-demo/run_all.sh +++ b/demos/orion-manual-demo/run_all.sh @@ -23,11 +23,11 @@ mkdir ./logs # COSMOS_PID=$! # run quasar and save pid -./quasar_localnet.sh & +../quasar_localnet.sh & QUASAR_PID=$! #run osmo and save pid -./osmo_localnet.sh & +../osmo_localnet.sh & OSMO_PID=$! # wait for chains to start diff --git a/demos/upgrade-handler/v1.0.0/README.md b/demos/upgrade-handler/v1.0.0/README.md index 122fc1ddd..b7a02cbb9 100644 --- a/demos/upgrade-handler/v1.0.0/README.md +++ b/demos/upgrade-handler/v1.0.0/README.md @@ -32,4 +32,66 @@ chmod +x upgrade_handler_v1_0_0.sh ```bash chmod +x restart_v1_0_0_binary.sh ./restart_v1_0_0_binary.sh -``` \ No newline at end of file +``` + +# How to test upgrade with Contracts in action + +Testing a software upgrade on a Cosmos-based chain with contracts involves several steps to ensure a smooth transition and verify that the upgrade process works correctly. Below is a detailed breakdown of each step: + +1. **Set Up Chains: Quasar and Osmosis** + Set up two chains, Quasar and Osmosis, using the appropriate network and node infrastructure. Ensure you have the required configurations and access to deploy contracts and perform transactions. + +2. **Set Up Relayer** + Configure and set up a relayer that can handle IBC (Inter-Blockchain Communication) transactions between the two chains. The relayer will play a crucial role in moving data between the chains during the upgrade process. + +3. **Deploy Pools on Osmosis** + Deploy liquidity pools or any other necessary contracts on the Osmosis chain. Ensure these contracts are functioning as expected before proceeding. + +4. **Perform IBC Transactions** + Initiate IBC transactions from Osmosis to Quasar's treasury account. This tests the cross-chain communication mechanism and verifies that funds can be moved securely. + +5. **Deploy Primitives** + Deploy any additional smart contracts or primitives required for your upgrade. These could be contract templates, modules, or any other logic needed for your application. + +6. **Deploy Vault** + Deploy a contract that represents the vault on the chain. This vault could be related to tokens, assets, or any other functionality your application requires. + +7. **Perform Bonding** + Perform a bond action to lock up a certain amount of tokens in the vault. This tests the bond mechanism and ensures that tokens are securely locked. + +8. **Query Bond Account Balance** + Use queries to check the balance of the bonded account in the vault. This verifies that the bond action was successful and the balance reflects the tokens that were bonded. + +9. **Post Software Upgrade Proposal** + Initiate a software upgrade proposal that includes the necessary upgrade parameters, including the new binary, upgrade plan, and any other relevant information. + +10. **Wait for Blocks** + Allow time for the network to process the software upgrade proposal. Wait for a sufficient number of blocks to pass to ensure the proposal is properly propagated and considered by validators. + +11. **Perform Binary Change** + Once the upgrade proposal passes the governance process, perform the binary change by applying the new version of the software to the chain's nodes. This step should be executed carefully to ensure a smooth transition. + +12. **Wait for Blocks to Pass** + After the binary change, wait for a few blocks to pass to ensure the new version of the software is functioning correctly and has been adopted by the majority of validators. + +13. **Perform Bond and Unbond** + Perform bonding and unbonding actions to test the functionality of the vault and ensure that tokens can be bonded and unbonded as intended. + +14. **Perform Claim** + Perform a claim action to retrieve any rewards or benefits from the vault. This ensures that the vault's claim mechanism is working as expected. + +Each of these steps involves both technical and functional testing to verify that the upgrade process is successful and the new software version functions correctly. It's important to have proper testing environments, test cases, and coordination with the network participants to ensure a successful software upgrade. + +## Steps + +- Download v0.1.1 from Quasar-preview repository +- Put this in your path and name it as `quasarnoded-go-18` +- Checkout to the v1 of Quasar and install it locally as `quasarnoded` +- Once the binaries are in place : + - Run : + ```shell + cd demos/upgrade-handler/v1.0.0 + sh test_upgrade_with_contracts.sh + ``` +- Once this start all the actions would pe performed automatically. Make sure to keep the contracts artifacts at the latest version in order to perform a good testing. +- Please perform all the other queries after the announcement of `test finished` in order to check all the actions are working properly diff --git a/demos/upgrade-handler/v1.0.0/go-relayer-config/chains/osmosis.json b/demos/upgrade-handler/v1.0.0/go-relayer-config/chains/osmosis.json new file mode 100644 index 000000000..80d038981 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/go-relayer-config/chains/osmosis.json @@ -0,0 +1,16 @@ +{ + "type": "cosmos", + "value": { + "key": "osmokey", + "chain-id": "osmosis", + "rpc-addr": "http://127.0.0.1:26679", + "account-prefix": "osmo", + "keyring-backend": "test", + "gas-adjustment": 1.3, + "gas-prices": "0.1uosmo", + "debug": true, + "timeout": "20s", + "output-format": "json", + "sign-mode": "direct" + } +} \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/go-relayer-config/chains/quasar.json b/demos/upgrade-handler/v1.0.0/go-relayer-config/chains/quasar.json new file mode 100644 index 000000000..af02f5a01 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/go-relayer-config/chains/quasar.json @@ -0,0 +1,16 @@ +{ + "type": "cosmos", + "value": { + "key": "quasarkey", + "chain-id": "quasar", + "rpc-addr": "http://localhost:26659", + "account-prefix": "quasar", + "keyring-backend": "test", + "gas-adjustment": 1.2, + "gas-prices": "0.01uqsr", + "debug": true, + "timeout": "20s", + "output-format": "json", + "sign-mode": "direct" + } +} \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/go-relayer-config/paths/quasar_osmosis.json b/demos/upgrade-handler/v1.0.0/go-relayer-config/paths/quasar_osmosis.json new file mode 100644 index 000000000..9cabcc088 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/go-relayer-config/paths/quasar_osmosis.json @@ -0,0 +1,12 @@ +{ + "src": { + "chain-id": "quasar" + }, + "dst": { + "chain-id": "osmosis" + }, + "src-channel-filter": { + "rule": null, + "channel-list": [] + } +} \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/go_relayer_setup.sh b/demos/upgrade-handler/v1.0.0/go_relayer_setup.sh new file mode 100755 index 000000000..ea4dad13c --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/go_relayer_setup.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# remove any old configs +RELAYER_CONF="$HOME/.relayer" +rm -rf $RELAYER_CONF &> /dev/null + +rly config init + +# add configs for each chain, +rly chains add-dir ./go-relayer-config/chains + +# restore the keys from the mnemomic phrases, same phrases as the hermes script +OSMOKEY="$(cat ./keys/osmo.key)" +QUASARKEY="$(cat ./keys/qsr.key)" + +rly keys restore quasar quasarkey "$QUASARKEY" +rly keys restore osmosis osmokey "$OSMOKEY" + +rly q balance quasar +rly q balance osmosis + +rly paths add-dir ./go-relayer-config/paths +rly tx link quasar_osmosis --debug --override >> ./logs/rly_qo_setup.log 2>&1 + diff --git a/demos/upgrade-handler/v1.0.0/keys/gaia.key b/demos/upgrade-handler/v1.0.0/keys/gaia.key new file mode 100644 index 000000000..a8cddb086 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/keys/gaia.key @@ -0,0 +1 @@ +ready hundred phrase theme bar breeze zone system bitter double flush deposit sugar swap burger outside primary nature attend caught wire ticket depth cycle diff --git a/demos/upgrade-handler/v1.0.0/keys/osmo.key b/demos/upgrade-handler/v1.0.0/keys/osmo.key new file mode 100644 index 000000000..771f7031a --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/keys/osmo.key @@ -0,0 +1 @@ +rabbit garlic monitor wish pony magic budget someone room torch celery empower word assume digital rack electric weapon urban foot sketch jelly wet myself diff --git a/demos/upgrade-handler/v1.0.0/keys/qsr.key b/demos/upgrade-handler/v1.0.0/keys/qsr.key new file mode 100644 index 000000000..d47463aa4 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/keys/qsr.key @@ -0,0 +1 @@ +old cinnamon boy hurry pipe upset exhibit title copy squirrel grit eye love toy cotton connect inhale cost quarter mistake ahead endless bless license diff --git a/demos/upgrade-handler/v1.0.0/osmo_localnet.sh b/demos/upgrade-handler/v1.0.0/osmo_localnet.sh new file mode 100755 index 000000000..9a4ba3967 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/osmo_localnet.sh @@ -0,0 +1,255 @@ +#!/bin/sh + +# Configure variables +BINARY=osmosisd +HOME_OSMOSIS=$HOME/.osmosis +CHAIN_ID=osmosis +ALICE="cruise scene law sea push expose scorpion wire trick repair wave quote task dose inner denial alpha favorite certain blouse motion flash split lunch" +BOB="lizard garlic canyon winner cheese tent drip task because ecology clay bridge junk critic track artefact gather harsh deliver unit vacant earth diesel stool" +USER_1="guard cream sadness conduct invite crumble clock pudding hole grit liar hotel maid produce squeeze return argue turtle know drive eight casino maze host" +USER_2="fuel obscure melt april direct second usual hair leave hobby beef bacon solid drum used law mercy worry fat super must ritual bring faculty" +RELAYER_ACC="$(cat ./keys/osmo.key)" + +ALICE_GENESIS_COINS=20000000uosmo,2000000000stake,1000000000000fakestake +BOB_GENESIS_COINS=10000000000000uosmo,1000000000stake,1000000000000fakestake,100000000000000usdc +USER_1_GENESIS_COINS=10000000000stake,10000000000uosmo +USER_2_GENESIS_COINS=10000000000stake,10000000000uosmo +RELAYER_ACC_GENESIS_COINS=10000000uosmo,10000000000stake + +echo $HOME_OSMOSIS + +rm -rf $HOME_OSMOSIS +# Bootstrap +$BINARY init $CHAIN_ID --chain-id $CHAIN_ID --home $HOME_OSMOSIS + +echo $ALICE | $BINARY keys add alice --keyring-backend test --recover --home $HOME_OSMOSIS +echo $BOB | $BINARY keys add bob --keyring-backend test --recover --home $HOME_OSMOSIS +echo $USER_1 | $BINARY keys add user1 --keyring-backend test --recover --home $HOME_OSMOSIS +echo $USER_2 | $BINARY keys add user2 --keyring-backend test --recover --home $HOME_OSMOSIS +echo $RELAYER_ACC | $BINARY keys add relayer_acc --keyring-backend test --recover --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show alice --keyring-backend test -a --home $HOME_OSMOSIS) $ALICE_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show bob --keyring-backend test -a --home $HOME_OSMOSIS) $BOB_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show user1 --keyring-backend test -a --home $HOME_OSMOSIS) $USER_1_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show user2 --keyring-backend test -a --home $HOME_OSMOSIS) $USER_2_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY add-genesis-account $($BINARY keys show relayer_acc --keyring-backend test -a --home $HOME_OSMOSIS) $RELAYER_ACC_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY add-genesis-account osmo15td5pfjkmfn8d6l4t8dc67l3apgt9epw4ct298 $RELAYER_ACC_GENESIS_COINS --home $HOME_OSMOSIS +$BINARY gentx alice 10000000uosmo --chain-id $CHAIN_ID --keyring-backend test --home $HOME_OSMOSIS +$BINARY collect-gentxs --home $HOME_OSMOSIS + +# Check platform +platform='unknown' +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + platform='linux' +elif [ "$unamestr" = 'Darwin' ]; then + platform='macos' +fi + +if [ $platform = 'linux' ]; then + sed -i 's/enable = false/enable = true/g' $HOME_OSMOSIS/config/app.toml + sed -i 's/swagger = false/swagger = true/g' $HOME_OSMOSIS/config/app.toml + sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0uosmo"/g' $HOME_OSMOSIS/config/app.toml + sed -i 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26679"+g' $HOME_OSMOSIS/config/config.toml + sed -i 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26679"+g' $HOME_OSMOSIS/config/client.toml + sed -i 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26662"+g' $HOME_OSMOSIS/config/config.toml + sed -i 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6062"+g' $HOME_OSMOSIS/config/config.toml + sed -i 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9096"+g' $HOME_OSMOSIS/config/app.toml + sed -i 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8092"+g' $HOME_OSMOSIS/config/app.toml + sed -i 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1312"+g' $HOME_OSMOSIS/config/app.toml + sed -i 's+address = ":8080"+address = ":8082"+g' $HOME_OSMOSIS/config/app.toml +elif [ $platform = 'macos' ]; then + sed -i'.original' -e 's/enable = false/enable = true/g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's/swagger = false/swagger = true/g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's/minimum-gas-prices = ""/minimum-gas-prices = "0uosmo"/g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26679"+g' $HOME_OSMOSIS/config/config.toml + sed -i'.original' -e 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26679"+g' $HOME_OSMOSIS/config/client.toml + sed -i'.original' -e 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26662"+g' $HOME_OSMOSIS/config/config.toml + sed -i'.original' -e 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6062"+g' $HOME_OSMOSIS/config/config.toml + sed -i'.original' -e 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9096"+g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8092"+g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1312"+g' $HOME_OSMOSIS/config/app.toml + sed -i'.original' -e 's+address = ":8080"+address = ":8082"+g' $HOME_OSMOSIS/config/app.toml +else + echo "only linux and macos platforms are supported, if you are using other platforms you should probably improve this script." + + exit 1 + sed -i '' 's/enable = false/enable = true/g' $HOME_OSMOSIS/config/app.toml + sed -i '' 's/swagger = false/swagger = true/g' $HOME_OSMOSIS/config/app.toml +fi + +cp $HOME_OSMOSIS/config/genesis.json $HOME_OSMOSIS/config/genesis_original.json +cat $HOME_OSMOSIS/config/genesis_original.json | + jq '.app_state.crisis.constant_fee.denom="uosmo"' | + jq '.app_state.staking.params.bond_denom="uosmo"' | + jq '.app_state.mint = { + minter: { + epoch_provisions: "0.000000000000000000" + }, + params: { + distribution_proportions: { + community_pool: "0.100000000000000000", + developer_rewards: "0.200000000000000000", + pool_incentives: "0.300000000000000000", + staking: "0.400000000000000000" + }, + epoch_identifier: "day", + genesis_epoch_provisions: "5000000.000000000000000000", + mint_denom: "uosmo", + minting_rewards_distribution_start_epoch: "0", + reduction_factor: "0.500000000000000000", + reduction_period_in_epochs: "156", + weighted_developer_rewards_receivers: [] + } + }' | + jq '.app_state.incentives = { + last_gauge_id: "0", + lockable_durations: [ + "1s", + "120s", + "180s", + "240s" + ], + params: { + distr_epoch_identifier: "day" + } + }' | + jq '.app_state.poolincentives = { + distr_info: { + records: [ + { + gauge_id: "0", + weight: "10000" + }, + { + gauge_id: "1", + weight: "1000" + }, + { + gauge_id: "2", + weight: "100" + } + ], + total_weight: "11100" + }, + lockable_durations: [ + "120s", + "180s", + "240s" + ], + params: { + minted_denom: "uosmo" + } + }' | + jq '.app_state.txfees.basedenom="uosmo"' | + jq '.app_state.gov.deposit_params.min_deposit=[{denom:"uosmo",amount:"1"}]' | + jq '.app_state.gov.voting_params.voting_period="30s"' | + jq '.app_state.gov.tally_params={quorum:"0.000000000000000001",threshold:"0.5",veto_threshold:"0.334"}' | + jq '.app_state.interchainaccounts = { + host_genesis_state: { + port: "icahost", + params: { + host_enabled: true, + allow_messages: [ + "/ibc.applications.transfer.v1.MsgTransfer", + "/cosmos.bank.v1beta1.MsgSend", + "/cosmos.staking.v1beta1.MsgDelegate", + "/cosmos.staking.v1beta1.MsgBeginRedelegate", + "/cosmos.staking.v1beta1.MsgCreateValidator", + "/cosmos.staking.v1beta1.MsgEditValidator", + "/cosmos.staking.v1beta1.MsgUndelegate", + "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", + "/cosmos.distribution.v1beta1.MsgSetWithdrawAddress", + "/cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission", + "/cosmos.distribution.v1beta1.MsgFundCommunityPool", + "/cosmos.gov.v1beta1.MsgVote", + "/osmosis.gamm.v1beta1.MsgJoinPool", + "/osmosis.gamm.v1beta1.MsgExitPool", + "/osmosis.gamm.v1beta1.MsgSwapExactAmountIn", + "/osmosis.gamm.v1beta1.MsgSwapExactAmountOut", + "/osmosis.gamm.v1beta1.MsgJoinSwapExternAmountIn", + "/osmosis.gamm.v1beta1.MsgJoinSwapShareAmountOut", + "/osmosis.gamm.v1beta1.MsgExitSwapExternAmountOut", + "/osmosis.gamm.v1beta1.MsgExitSwapShareAmountIn", + "/osmosis.lockup.MsgBeginUnlocking", + "/osmosis.lockup.MsgLockTokens", + "/osmosis.superfluid.MsgSuperfluidUnbondLock" + ] + } + } + }' | + jq '.app_state.interchainquery = { + host_port: "icqhost", + params: { + host_enabled: true, + allow_queries: [ + "/ibc.applications.transfer.v1.Query/DenomTrace", + "/cosmos.auth.v1beta1.Query/Account", + "/cosmos.auth.v1beta1.Query/Params", + "/cosmos.bank.v1beta1.Query/Balance", + "/cosmos.bank.v1beta1.Query/DenomMetadata", + "/cosmos.bank.v1beta1.Query/Params", + "/cosmos.bank.v1beta1.Query/SupplyOf", + "/cosmos.distribution.v1beta1.Query/Params", + "/cosmos.distribution.v1beta1.Query/DelegatorWithdrawAddress", + "/cosmos.distribution.v1beta1.Query/ValidatorCommission", + "/cosmos.gov.v1beta1.Query/Deposit", + "/cosmos.gov.v1beta1.Query/Params", + "/cosmos.gov.v1beta1.Query/Vote", + "/cosmos.slashing.v1beta1.Query/Params", + "/cosmos.slashing.v1beta1.Query/SigningInfo", + "/cosmos.staking.v1beta1.Query/Delegation", + "/cosmos.staking.v1beta1.Query/Params", + "/cosmos.staking.v1beta1.Query/Validator", + "/osmosis.epochs.v1beta1.Query/EpochInfos", + "/osmosis.epochs.v1beta1.Query/CurrentEpoch", + "/osmosis.gamm.v1beta1.Query/NumPools", + "/osmosis.gamm.v1beta1.Query/TotalLiquidity", + "/osmosis.gamm.v1beta1.Query/Pool", + "/osmosis.gamm.v1beta1.Query/PoolParams", + "/osmosis.gamm.v1beta1.Query/TotalPoolLiquidity", + "/osmosis.gamm.v1beta1.Query/TotalShares", + "/osmosis.gamm.v1beta1.Query/CalcJoinPoolShares", + "/osmosis.gamm.v1beta1.Query/CalcExitPoolCoinsFromShares", + "/osmosis.gamm.v1beta1.Query/CalcJoinPoolNoSwapShares", + "/osmosis.gamm.v1beta1.Query/PoolType", + "/osmosis.gamm.v2.Query/SpotPrice", + "/osmosis.gamm.v1beta1.Query/EstimateSwapExactAmountIn", + "/osmosis.gamm.v1beta1.Query/EstimateSwapExactAmountOut", + "/osmosis.incentives.Query/ModuleToDistributeCoins", + "/osmosis.incentives.Query/LockableDurations", + "/osmosis.lockup.Query/ModuleBalance", + "/osmosis.lockup.Query/ModuleLockedAmount", + "/osmosis.lockup.Query/AccountUnlockableCoins", + "/osmosis.lockup.Query/AccountUnlockingCoins", + "/osmosis.lockup.Query/LockedDenom", + "/osmosis.lockup.Query/LockedByID", + "/osmosis.lockup.Query/NextLockID", + "/osmosis.mint.v1beta1.Query/EpochProvisions", + "/osmosis.mint.v1beta1.Query/Params", + "/osmosis.poolincentives.v1beta1.Query/GaugeIds", + "/osmosis.superfluid.Query/Params", + "/osmosis.superfluid.Query/AssetType", + "/osmosis.superfluid.Query/AllAssets", + "/osmosis.superfluid.Query/AssetMultiplier", + "/osmosis.poolmanager.v1beta1.Query/NumPools", + "/osmosis.poolmanager.v1beta1.Query/EstimateSwapExactAmountIn", + "/osmosis.poolmanager.v1beta1.Query/EstimateSwapExactAmountOut", + "/osmosis.txfees.v1beta1.Query/FeeTokens", + "/osmosis.txfees.v1beta1.Query/DenomSpotPrice", + "/osmosis.txfees.v1beta1.Query/DenomPoolId", + "/osmosis.txfees.v1beta1.Query/BaseDenom", + "/osmosis.tokenfactory.v1beta1.Query/Params", + "/osmosis.tokenfactory.v1beta1.Query/DenomAuthorityMetadata", + "/osmosis.twap.v1beta1.Query/ArithmeticTwap", + "/osmosis.twap.v1beta1.Query/ArithmeticTwapToNow", + "/osmosis.twap.v1beta1.Query/GeometricTwap", + "/osmosis.twap.v1beta1.Query/GeometricTwapToNow", + "/osmosis.twap.v1beta1.Query/Params", + "/osmosis.downtimedetector.v1beta1.Query/RecoveredSinceDowntimeOfLength" + ] + } + }' \ + >$HOME_OSMOSIS/config/genesis.json + +# Start +$BINARY start --home $HOME_OSMOSIS >>./logs/osmo_localnet.log 2>&1 diff --git a/demos/upgrade-handler/v1.0.0/pools/sample_pool1.json b/demos/upgrade-handler/v1.0.0/pools/sample_pool1.json new file mode 100644 index 000000000..0b00652ec --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/pools/sample_pool1.json @@ -0,0 +1,7 @@ +{ + "weights": "4stake,4uosmo", + "initial-deposit": "100000000stake,100000000uosmo", + "swap-fee": "0.01", + "exit-fee": "0.0", + "future-governor": "168h" +} \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/pools/sample_pool2.json b/demos/upgrade-handler/v1.0.0/pools/sample_pool2.json new file mode 100644 index 000000000..0d761dbd7 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/pools/sample_pool2.json @@ -0,0 +1,7 @@ +{ + "weights": "4uosmo,4usdc", + "initial-deposit": "100000000uosmo,100000000usdc", + "swap-fee": "0.01", + "exit-fee": "0.0", + "future-governor": "168h" +} \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/pools/sample_pool3.json b/demos/upgrade-handler/v1.0.0/pools/sample_pool3.json new file mode 100644 index 000000000..cf2bb2fba --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/pools/sample_pool3.json @@ -0,0 +1,7 @@ +{ + "weights": "4fakestake,4uosmo", + "initial-deposit": "100000000fakestake,100000000uosmo", + "swap-fee": "0.01", + "exit-fee": "0.0", + "future-governor": "168h" +} \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/post_upgrade.sh b/demos/upgrade-handler/v1.0.0/post_upgrade.sh new file mode 100755 index 000000000..edc27c9ea --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/post_upgrade.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +## env variables +BINARY=quasarnoded +CHAIN_ID="quasar" +ACCOUNT_NAME="my_treasury" +RPC="http://127.0.0.1:26659" + +# let the chain start after upgrade and produce some blocks +sleep 15 + +echo "perform a claim on the account an unbond before chain upgrade" +$BINARY tx wasm execute $VAULT_ADDR '{"claim":{}}' --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id quasar --fees 10000uqsr --gas 7000000 --node $RPC + +sleep 60 + +echo "query bank balance" +$BINARY query bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node $RPC + +# perform bonding again to see if it is working +echo "perform another bond after chain upgrade" +$BINARY tx wasm execute $VAULT_ADDR '{"bond":{}}' --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --amount 10000000ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518 --node $RPC + +sleep 120 + +echo "query the balance after the bond" +$BINARY query wasm contract-state smart $VAULT_ADDR '{"balance":{"address":"quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec"}}' --node $RPC + + +echo "perform an unbond action on new bond" +$BINARY tx wasm execute $VAULT_ADDR '{"unbond":{"amount":"9999999"}}' --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id quasar --fees 10000uqsr --gas 7000000 --node $RPC + +sleep 60 + +echo "perform a claim" +$BINARY tx wasm execute $VAULT_ADDR '{"claim":{}}' --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id quasar --fees 10000uqsr --gas 7000000 --node $RPC + +sleep 60 + +echo "query bank balance" +$BINARY query bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node $RPC \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/pre_upgrade.sh b/demos/upgrade-handler/v1.0.0/pre_upgrade.sh new file mode 100755 index 000000000..080ca7b77 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/pre_upgrade.sh @@ -0,0 +1,110 @@ +#!/bin/sh + +set -e + +on_error() { + echo "Some error occurred" + + quasarnoded q wasm contract-state smart $ADDR1 '{"trapped_errors":{}}' + + afplay /System/Library/Sounds/Sosumi.aiff +} + +trap 'on_error' ERR + +# create a pool on osmosis to test against +osmosisd tx gamm create-pool --pool-file ./pools/sample_pool1.json --node http://127.0.0.1:26679 --from bob --keyring-backend test --home $HOME/.osmosis --chain-id osmosis -y --gas-prices 1uosmo -b block +osmosisd tx gamm create-pool --pool-file ./pools/sample_pool2.json --node http://127.0.0.1:26679 --from bob --keyring-backend test --home $HOME/.osmosis --chain-id osmosis -y --gas-prices 1uosmo -b block +osmosisd tx gamm create-pool --pool-file ./pools/sample_pool3.json --node http://127.0.0.1:26679 --from bob --keyring-backend test --home $HOME/.osmosis --chain-id osmosis -y --gas-prices 1uosmo -b block + +echo "ibc transferring uosmo" +osmosisd tx ibc-transfer transfer transfer channel-0 quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 10000000000uosmo --from bob --keyring-backend test --home $HOME/.osmosis --node http://127.0.0.1:26679 --chain-id osmosis -y --gas-prices 1uosmo +sleep 6 +osmosisd tx ibc-transfer transfer transfer channel-0 quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 1000002stake --from bob --keyring-backend test --home $HOME/.osmosis --node http://127.0.0.1:26679 --chain-id osmosis -y --gas-prices 1uosmo +sleep 6 +osmosisd tx ibc-transfer transfer transfer channel-0 quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 1000003fakestake --from bob --keyring-backend test --home $HOME/.osmosis --node http://127.0.0.1:26679 --chain-id osmosis -y --gas-prices 1uosmo +sleep 6 + +# lock_period is 60 for 60 sec, in prod should be at least: 60 sec/min * 60 min/hr * 24hr * 14days "1209600" +# pool_id is hardcoded to 1 for this testing setup, expected to be done by the instantiater on local/testnet +# pool_denom should be looked up and hardcoded aswell +# base_denom: base_denom should be the denom of the token on osmosos, for now uosmo +# local_denom: the denom of the token used locally, in this testing case: the denom of the path transfer/channel-1/uosmo +# quote_denom is the denom other denom in the pool, stake for now +INIT1='{"lock_period":6,"pool_id":1,"pool_denom":"gamm/pool/1","base_denom":"uosmo","local_denom":"ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518","quote_denom":"stake","return_source_channel":"channel-0","transfer_channel":"channel-0","expected_connection":"connection-0"}' +INIT2='{"lock_period":6,"pool_id":3,"pool_denom":"gamm/pool/3","base_denom":"uosmo","local_denom":"ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518","quote_denom":"fakestake","return_source_channel":"channel-0","transfer_channel":"channel-0","expected_connection":"connection-0"}' +INIT3='{"lock_period":6,"pool_id":2,"pool_denom":"gamm/pool/2","base_denom":"uosmo","local_denom":"ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518","quote_denom":"usdc","return_source_channel":"channel-0","transfer_channel":"channel-0","expected_connection":"connection-0"}' + +# shellcheck disable=SC2164 +cd ../../../smart-contracts + +docker run --rm -v "$(pwd)":/code --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry cosmwasm/workspace-optimizer-arm64:0.12.11 + +BINARY=quasarnoded-go-18 +CHAIN_ID="quasar" +ACCOUNT_NAME="my_treasury" +ACCOUNT_ADDRESS="quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec" +RPC="http://127.0.0.1:26659" + +$BINARY query bank balances quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec --node "http://127.0.0.1:26659" + +RES=$($BINARY tx wasm store artifacts/lp_strategy-aarch64.wasm --from $ACCOUNT_NAME --keyring-backend test -y -b block --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --node $RPC) +CODE_ID=$(echo $RES | jq -r '.logs[0].events[-1].attributes[1].value') +echo "Got CODE_ID = $CODE_ID" + +echo "Deploying primitives" +echo "Primitive 1" +OUT1=$($BINARY tx wasm instantiate $CODE_ID "$INIT1" --from $ACCOUNT_NAME --keyring-backend test --label "primitive-1" -b block -y --admin $ACCOUNT_ADDRESS --chain-id $CHAIN_ID --gas 7000000 --fees 10000uqsr --node $RPC) +ADDR1=$($BINARY query wasm list-contract-by-code $CODE_ID --output json | jq -r '.contracts[0]') +echo "Got address of primitive 1 contract = $ADDR1" + +rly transact channel quasar_osmosis --src-port "wasm.$ADDR1" --dst-port icqhost --order unordered --version icq-1 --override +rly transact channel quasar_osmosis --src-port "wasm.$ADDR1" --dst-port icahost --order ordered --version '{"version":"ics27-1","encoding":"proto3","tx_type":"sdk_multi_msg","controller_connection_id":"connection-0","host_connection_id":"connection-0"}' --override + +echo "Primitive 2" +OUT2=$($BINARY tx wasm instantiate $CODE_ID "$INIT2" --from $ACCOUNT_NAME --keyring-backend test --label "primitive-1" -b block -y --admin $ACCOUNT_ADDRESS --chain-id $CHAIN_ID --gas 7000000 --fees 10000uqsr --node $RPC) +ADDR2=$($BINARY query wasm list-contract-by-code $CODE_ID --output json | jq -r '.contracts[1]') +echo "Got address of primitive 2 contract = $ADDR2" + +rly transact channel quasar_osmosis --src-port "wasm.$ADDR2" --dst-port icqhost --order unordered --version icq-1 --override +rly transact channel quasar_osmosis --src-port "wasm.$ADDR2" --dst-port icahost --order ordered --version '{"version":"ics27-1","encoding":"proto3","tx_type":"sdk_multi_msg","controller_connection_id":"connection-0","host_connection_id":"connection-0"}' --override + +echo "Primitive 3" +OUT3=$($BINARY tx wasm instantiate $CODE_ID "$INIT3" --from $ACCOUNT_NAME --keyring-backend test --label "primitive-1" -b block -y --admin $ACCOUNT_ADDRESS --chain-id $CHAIN_ID --gas 7000000 --fees 10000uqsr --node $RPC) +ADDR3=$($BINARY query wasm list-contract-by-code $CODE_ID --output json | jq -r '.contracts[2]') +echo "Got address of primitive 3 contract = $ADDR3" + +rly transact channel quasar_osmosis --src-port "wasm.$ADDR3" --dst-port icqhost --order unordered --version icq-1 --override +rly transact channel quasar_osmosis --src-port "wasm.$ADDR3" --dst-port icahost --order ordered --version '{"version":"ics27-1","encoding":"proto3","tx_type":"sdk_multi_msg","controller_connection_id":"connection-0","host_connection_id":"connection-0"}' --override + +echo "Store vault rewards code" +RES=$($BINARY tx wasm store artifacts/vault_rewards-aarch64.wasm --from $ACCOUNT_NAME --keyring-backend test -y -b block --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --node $RPC) +VR_CODE_ID=$(echo $RES | jq -r '.logs[0].events[-1].attributes[1].value') +echo "Got vault rewards code ID = $VR_CODE_ID" + +echo "Running store code for vault" +RES=$($BINARY tx wasm store artifacts/basic_vault-aarch64.wasm --from $ACCOUNT_NAME --keyring-backend test -y -b block --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --node $RPC) +VAULT_CODE_ID=$(echo $RES | jq -r '.logs[0].events[-1].attributes[1].value') +echo "Got basic vault CODE_ID = $VAULT_CODE_ID" + +VAULT_INIT='{"total_cap":"200000000000","thesis":"test vault","vault_rewards_code_id":'$VR_CODE_ID',"reward_token":{"native":"uqsr"},"reward_distribution_schedules":[],"decimals":6,"symbol":"OPRO","min_withdrawal":"1","name":"OPRO","deposit_denom":"ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518","primitives":[{"address":"'$ADDR1'","weight":"0.333333333333","init":{"l_p":'$INIT1'}},{"address":"'$ADDR2'","weight":"0.333333333333","init":{"l_p":'$INIT2'}},{"address":"'$ADDR3'","weight":"0.333333333333","init":{"l_p":'$INIT3'}}]}' +OUT=$($BINARY tx wasm instantiate $VAULT_CODE_ID "$VAULT_INIT" --from $ACCOUNT_NAME --keyring-backend test --label "vault 1" -b block -y --admin $ACCOUNT_ADDRESS --chain-id $CHAIN_ID --gas 7000000 --fees 10000uqsr --node $RPC) +VAULT_ADDR=$($BINARY query wasm list-contract-by-code $VAULT_CODE_ID --output json $NODE | jq -r '.contracts[0]') +echo "Got address of deployed vault contract address = $VAULT_ADDR" + +echo "setting depositor" +$BINARY tx wasm execute $ADDR1 '{"set_depositor":{"depositor":"'$VAULT_ADDR'"}}' --from $ACCOUNT_NAME --keyring-backend test -y -b block --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 +$BINARY tx wasm execute $ADDR2 '{"set_depositor":{"depositor":"'$VAULT_ADDR'"}}' --from $ACCOUNT_NAME --keyring-backend test -y -b block --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 +$BINARY tx wasm execute $ADDR3 '{"set_depositor":{"depositor":"'$VAULT_ADDR'"}}' --from $ACCOUNT_NAME --keyring-backend test -y -b block --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 + +echo "perform a bond action" +$BINARY tx wasm execute $VAULT_ADDR '{"bond":{}}' --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --amount 10000000ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518 --node $RPC + +sleep 120 + +echo "query balance of the bonding account on vault" +$BINARY query wasm contract-state smart $VAULT_ADDR '{"balance":{"address":"quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec"}}' + +echo "perform an unbond action right befor chain upgrade" +$BINARY tx wasm execute $VAULT_ADDR '{"unbond":{"amount":"9000000"}}' --from $ACCOUNT_NAME --keyring-backend test -y -b block --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --node $RPC + diff --git a/demos/upgrade-handler/v1.0.0/quasar_localnet.sh b/demos/upgrade-handler/v1.0.0/quasar_localnet.sh new file mode 100755 index 000000000..883c81e82 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/quasar_localnet.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +## This script helps to create a basic version of the quasar chain genesis file for development purposes. +## However it will need some manual modifications before you start the chain to incorporate the custom fields. + +# Configure variables +BINARY=quasarnoded-go-18 +HOME_QSR=$HOME/.quasarnode +CHAIN_ID=quasar +MY_TREASURY="edge victory hurry slight dog exit company bike hill erupt shield aspect turkey retreat stairs summer sadness crush absorb draft viable orphan chuckle exhibit" +MY_TREASURY_GENESIS_COINS=20000token,200000000stake,1000000000000uqsr + +RELAYER_ACC="$(cat ./keys/qsr.key)" +RELAYER_ACC_GENESIS_COINS=10000000uqsr,10000000000stake + +# Remove previous setup + +rm -rf $HOME_QSR + +$BINARY init $CHAIN_ID --chain-id $CHAIN_ID --home $HOME_QSR + +# Bootstrap the quasar local network with single node + +echo $MY_TREASURY | $BINARY keys add my_treasury --keyring-backend test --recover +echo $RELAYER_ACC | $BINARY keys add relayer_acc --keyring-backend test --recover + +$BINARY add-genesis-account $($BINARY keys show my_treasury --keyring-backend test -a) $MY_TREASURY_GENESIS_COINS +$BINARY add-genesis-account $($BINARY keys show relayer_acc --keyring-backend test -a) $RELAYER_ACC_GENESIS_COINS + +echo "Creating gentx" +$BINARY gentx my_treasury 100000000uqsr --chain-id $CHAIN_ID --keyring-backend test +echo "Collecting gentx" +$BINARY collect-gentxs + +# Check platform +platform='unknown' +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + platform='linux' +elif [ "$unamestr" = 'Darwin' ]; then + platform='macos' +fi + +if [ $platform = 'linux' ]; then + sed -i 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0uqsr"/g' $HOME_QSR/config/app.toml + sed -i 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +elif [ $platform = 'macos' ]; then + sed -i'.original' -e 's/enable = false/enable = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/swagger = false/swagger = true/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's/minimum-gas-prices = ""/minimum-gas-prices = "0uatom"/g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+laddr = "tcp://127.0.0.1:26657"+laddr = "tcp://127.0.0.1:26659"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+node = "tcp://localhost:26657"+node = "tcp://localhost:26659"+g' $HOME_QSR/config/client.toml + sed -i'.original' -e 's+laddr = "tcp://0.0.0.0:26656"+laddr = "tcp://0.0.0.0:26661"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+pprof_laddr = "localhost:6060"+pprof_laddr = "localhost:6061"+g' $HOME_QSR/config/config.toml + sed -i'.original' -e 's+address = "0.0.0.0:9090"+address = "0.0.0.0:9095"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "0.0.0.0:9091"+address = "0.0.0.0:8091"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = "tcp://0.0.0.0:1317"+address = "tcp://0.0.0.0:1311"+g' $HOME_QSR/config/app.toml + sed -i'.original' -e 's+address = ":8080"+address = ":8081"+g' $HOME_QSR/config/app.toml +else + echo "only linux and macos platforms are supported, if you are using other platforms you should probably improve this script." + exit 1 +fi + +cp $HOME_QSR/config/genesis.json $HOME_QSR/config/genesis_original.json +cat $HOME_QSR/config/genesis_original.json | + jq '.app_state.crisis.constant_fee.denom="uqsr"' | + jq '.app_state.staking.params.bond_denom="uqsr"' | + jq '.app_state.mint.params.mint_denom="uqsr"' | + jq '.app_state.gov.deposit_params.min_deposit=[{denom:"uqsr",amount:"1"}]' | + jq '.app_state.gov.voting_params.voting_period="60s"' | + jq '.app_state.gov.tally_params={quorum:"0.000000000000000001",threshold:"0.5",veto_threshold:"0.334"}' | + jq '.app_state.orion = { + "lpPosition": null, + "lpStat": null, + "params": { + "destination_chain_id": "osmosis", + "enabled": true, + "lp_epoch_id": "minute", + "mgmt_fee_per": "0.003000000000000000", + "osmosis_local_info": { + "chain_id": "osmosis", + "connection_id": "connection-1", + "local_zone_id": "osmosis-1" + }, + "perf_fee_per": "0.020000000000000000", + "white_listed_pools": [ + 1, + 2, + 3 + ] + }, + "rewardCollection": null + }' | + jq '.app_state.qbank = { + "claimableRewards": [], + "depositInfos": [], + "params": { + "enabled": true, + "min_orion_epoch_denom_dollar_deposit": "100.000000000000000000", + "orion_epoch_identifier": "minute", + "white_listed_denoms_in_orion": [ + { + "onehop_osmo": "ibc/BE1BB42D4BE3C30D50B68D7C41DB4DFCE9678E8EF8C539F6E6A9345048894FCC", + "onehop_quasar": "ibc/BE1BB42D4BE3C30D50B68D7C41DB4DFCE9678E8EF8C539F6E6A9345048894FCC", + "origin_name": "uatom" + } + ] + }, + "totalClaimedRewards": [], + "totalDeposits": [], + "totalWithdraws": [], + "withdrawables": [] + }' > $HOME_QSR/config/genesis.json + +# Start +echo "Starting the chain" +$BINARY start --home $HOME_QSR >>./logs/quasar.log 2>&1 diff --git a/demos/upgrade-handler/v1.0.0/upgrade.sh b/demos/upgrade-handler/v1.0.0/upgrade.sh new file mode 100755 index 000000000..8b740aa74 --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/upgrade.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +## run chain upgrade procedure +echo "RUNNING CHAIN UPGRADE PROCEDURE" +BINARY=quasarnoded-go-18 +CHAIN_ID="quasar" +ACCOUNT_NAME="my_treasury" +RPC="http://127.0.0.1:26659" +CURRENT_BLOCK=$($BINARY status | jq -r '.SyncInfo.latest_block_height') +CHAIN_ID=quasar +NUM1=20 +UPGRADE_HEIGHT=$(expr $NUM1 + $CURRENT_BLOCK) +echo $UPGRADE_HEIGHT + +# Submit governance proposal for software-upgrade to v1 +echo ">>> Submitting proposal for software-upgrade" +$BINARY tx gov submit-proposal software-upgrade "v1" --title "Software Upgrade to v1" --description "This software-upgrade v1 introduces qvesting, token factory and authx module" --upgrade-height $UPGRADE_HEIGHT --deposit 100uqsr --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --node $RPC + +sleep 5 + +echo ">>> Voting yes to proposal" +$BINARY tx gov vote 1 yes --from my_treasury --chain-id $CHAIN_ID --keyring-backend test -y + +echo ">>> Sleeping 5 seconds after voting proposal" +sleep 5 + +# Wait for the block height to reach the upgrade height +echo ">>> Waiting for the block height to reach $UPGRADE_HEIGHT" +while true; do + CURRENT_HEIGHT=$($BINARY status | jq -r '.SyncInfo.latest_block_height') + echo "Current height: ""$CURRENT_HEIGHT" + if [ "$CURRENT_HEIGHT" -ge "$UPGRADE_HEIGHT" ]; then + break + fi + sleep 5 +done + +echo "Check if the upgrade proposal works." +$BINARY query gov proposal 1 --chain-id $CHAIN_ID --output json + +sleep 30 + +echo "killing the old quasar instance to start the new one" +pkill quasarnoded +rm ./logs/quasar.log + +# run chain upgrade +BINARY=quasarnoded +HOME_QSR=$HOME/.quasarnode + +echo "starting with new binary" +$BINARY start --home $HOME_QSR >>./logs/quasar.log 2>&1 From b916a891181b441300fd0b2bf49a426423892515 Mon Sep 17 00:00:00 2001 From: Arham Chordia <43543921+arhamchordia@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:41:07 +0530 Subject: [PATCH 5/7] Adding missing file. --- .../v1.0.0/test_upgrade_with_contracts.sh | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh diff --git a/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh b/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh new file mode 100644 index 000000000..0453353cd --- /dev/null +++ b/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +# trap ctrl-c and ctrl-d +cleanup() { + kill $OSMO_PID + kill $QUASAR_PID + kill $RLY_PID_1 + kill $QUASAR_PID_1 +} + +trap cleanup 1 2 3 6 + +# reset logs dir +rm -rf ./logs +mkdir ./logs + +# run quasar and save pid +./quasar_localnet.sh & +QUASAR_PID=$! + +#run osmo and save pid +./osmo_localnet.sh & +OSMO_PID=$! + +# wait for chains to start +sleep 10 + +echo "setting up go relayer" +./go_relayer_setup.sh + +echo "starting go relaying" +# run an instance of go relayer for each path, thus 3 in total +rly start quasar_osmosis --debug-addr "localhost:7598" -p events --time-threshold 300s >>./logs/quasar_osmosis.log 2>&1 & +RLY_PID_1=$! + +quasarnoded status +osmosisd status + +# run pre upgrade actions like pools creation, contract deployments and bonding actions +./pre_upgrade.sh + +# run upgrade part that performs a chain upgrade +./upgrade.sh & +QUASAR_PID=$! + +# run post upgrade actions like new bonds, unbond and claim. +./post_upgrade.sh + +# Check platform +platform='unknown' +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + platform='linux' +elif [ "$unamestr" = 'Darwin' ]; then + platform='macos' +fi + +if [ $platform = 'macos' ]; then + say "test finished" +fi + +## wait is added so that the all the processes are not killed. +## please perform all the other queries after the announcement of test finished in order to check all the actions are working properly +wait From 3f6341157d95d149754b84974a915dfb48bee0ea Mon Sep 17 00:00:00 2001 From: Arham Chordia <43543921+arhamchordia@users.noreply.github.com> Date: Tue, 8 Aug 2023 22:00:31 +0530 Subject: [PATCH 6/7] Fixing tests. --- demos/upgrade-handler/v1.0.0/post_upgrade.sh | 3 ++- demos/upgrade-handler/v1.0.0/pre_upgrade.sh | 14 +++++++++----- .../v1.0.0/test_upgrade_with_contracts.sh | 14 +++++++++----- demos/upgrade-handler/v1.0.0/upgrade.sh | 9 ++++++--- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/demos/upgrade-handler/v1.0.0/post_upgrade.sh b/demos/upgrade-handler/v1.0.0/post_upgrade.sh index edc27c9ea..eabcfe51b 100755 --- a/demos/upgrade-handler/v1.0.0/post_upgrade.sh +++ b/demos/upgrade-handler/v1.0.0/post_upgrade.sh @@ -5,11 +5,12 @@ BINARY=quasarnoded CHAIN_ID="quasar" ACCOUNT_NAME="my_treasury" RPC="http://127.0.0.1:26659" +echo "Vault address : $VAULT_ADDR" # let the chain start after upgrade and produce some blocks sleep 15 -echo "perform a claim on the account an unbond before chain upgrade" +echo "perform a claim for an unbond made before the chain upgrade" $BINARY tx wasm execute $VAULT_ADDR '{"claim":{}}' --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id quasar --fees 10000uqsr --gas 7000000 --node $RPC sleep 60 diff --git a/demos/upgrade-handler/v1.0.0/pre_upgrade.sh b/demos/upgrade-handler/v1.0.0/pre_upgrade.sh index 080ca7b77..09c11e472 100755 --- a/demos/upgrade-handler/v1.0.0/pre_upgrade.sh +++ b/demos/upgrade-handler/v1.0.0/pre_upgrade.sh @@ -13,9 +13,12 @@ on_error() { trap 'on_error' ERR # create a pool on osmosis to test against -osmosisd tx gamm create-pool --pool-file ./pools/sample_pool1.json --node http://127.0.0.1:26679 --from bob --keyring-backend test --home $HOME/.osmosis --chain-id osmosis -y --gas-prices 1uosmo -b block -osmosisd tx gamm create-pool --pool-file ./pools/sample_pool2.json --node http://127.0.0.1:26679 --from bob --keyring-backend test --home $HOME/.osmosis --chain-id osmosis -y --gas-prices 1uosmo -b block -osmosisd tx gamm create-pool --pool-file ./pools/sample_pool3.json --node http://127.0.0.1:26679 --from bob --keyring-backend test --home $HOME/.osmosis --chain-id osmosis -y --gas-prices 1uosmo -b block +osmosisd tx gamm create-pool --pool-file ./pools/sample_pool1.json --node http://127.0.0.1:26679 --from bob --keyring-backend test --home $HOME/.osmosis --chain-id osmosis -y --gas-prices 1uosmo +sleep 6 +osmosisd tx gamm create-pool --pool-file ./pools/sample_pool2.json --node http://127.0.0.1:26679 --from bob --keyring-backend test --home $HOME/.osmosis --chain-id osmosis -y --gas-prices 1uosmo +sleep 6 +osmosisd tx gamm create-pool --pool-file ./pools/sample_pool3.json --node http://127.0.0.1:26679 --from bob --keyring-backend test --home $HOME/.osmosis --chain-id osmosis -y --gas-prices 1uosmo +sleep 6 echo "ibc transferring uosmo" osmosisd tx ibc-transfer transfer transfer channel-0 quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 10000000000uosmo --from bob --keyring-backend test --home $HOME/.osmosis --node http://127.0.0.1:26679 --chain-id osmosis -y --gas-prices 1uosmo @@ -23,7 +26,6 @@ sleep 6 osmosisd tx ibc-transfer transfer transfer channel-0 quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 1000002stake --from bob --keyring-backend test --home $HOME/.osmosis --node http://127.0.0.1:26679 --chain-id osmosis -y --gas-prices 1uosmo sleep 6 osmosisd tx ibc-transfer transfer transfer channel-0 quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec 1000003fakestake --from bob --keyring-backend test --home $HOME/.osmosis --node http://127.0.0.1:26679 --chain-id osmosis -y --gas-prices 1uosmo -sleep 6 # lock_period is 60 for 60 sec, in prod should be at least: 60 sec/min * 60 min/hr * 24hr * 14days "1209600" # pool_id is hardcoded to 1 for this testing setup, expected to be done by the instantiater on local/testnet @@ -89,6 +91,7 @@ echo "Got basic vault CODE_ID = $VAULT_CODE_ID" VAULT_INIT='{"total_cap":"200000000000","thesis":"test vault","vault_rewards_code_id":'$VR_CODE_ID',"reward_token":{"native":"uqsr"},"reward_distribution_schedules":[],"decimals":6,"symbol":"OPRO","min_withdrawal":"1","name":"OPRO","deposit_denom":"ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518","primitives":[{"address":"'$ADDR1'","weight":"0.333333333333","init":{"l_p":'$INIT1'}},{"address":"'$ADDR2'","weight":"0.333333333333","init":{"l_p":'$INIT2'}},{"address":"'$ADDR3'","weight":"0.333333333333","init":{"l_p":'$INIT3'}}]}' OUT=$($BINARY tx wasm instantiate $VAULT_CODE_ID "$VAULT_INIT" --from $ACCOUNT_NAME --keyring-backend test --label "vault 1" -b block -y --admin $ACCOUNT_ADDRESS --chain-id $CHAIN_ID --gas 7000000 --fees 10000uqsr --node $RPC) +export VAULT_ADDR="" VAULT_ADDR=$($BINARY query wasm list-contract-by-code $VAULT_CODE_ID --output json $NODE | jq -r '.contracts[0]') echo "Got address of deployed vault contract address = $VAULT_ADDR" @@ -106,5 +109,6 @@ echo "query balance of the bonding account on vault" $BINARY query wasm contract-state smart $VAULT_ADDR '{"balance":{"address":"quasar1sqlsc5024sszglyh7pswk5hfpc5xtl77gqjwec"}}' echo "perform an unbond action right befor chain upgrade" -$BINARY tx wasm execute $VAULT_ADDR '{"unbond":{"amount":"9000000"}}' --from $ACCOUNT_NAME --keyring-backend test -y -b block --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --node $RPC +$BINARY tx wasm execute $VAULT_ADDR '{"unbond":{"amount":"9000000"}}' --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --node $RPC +cd ../demos/upgrade-handler/v1.0.0 \ No newline at end of file diff --git a/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh b/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh index 0453353cd..d5e6ae297 100644 --- a/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh +++ b/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh @@ -5,9 +5,14 @@ cleanup() { kill $OSMO_PID kill $QUASAR_PID kill $RLY_PID_1 - kill $QUASAR_PID_1 } +pkill quasarnoded +pkill osmosisd +pkill rly + +sleep 3 + trap cleanup 1 2 3 6 # reset logs dir @@ -37,14 +42,13 @@ quasarnoded status osmosisd status # run pre upgrade actions like pools creation, contract deployments and bonding actions -./pre_upgrade.sh +. ./pre_upgrade.sh # run upgrade part that performs a chain upgrade -./upgrade.sh & -QUASAR_PID=$! +. ./upgrade.sh # run post upgrade actions like new bonds, unbond and claim. -./post_upgrade.sh +. ./post_upgrade.sh # Check platform platform='unknown' diff --git a/demos/upgrade-handler/v1.0.0/upgrade.sh b/demos/upgrade-handler/v1.0.0/upgrade.sh index 8b740aa74..ce36503ba 100755 --- a/demos/upgrade-handler/v1.0.0/upgrade.sh +++ b/demos/upgrade-handler/v1.0.0/upgrade.sh @@ -12,11 +12,14 @@ NUM1=20 UPGRADE_HEIGHT=$(expr $NUM1 + $CURRENT_BLOCK) echo $UPGRADE_HEIGHT +# sleep for a few seconds after the previous file transaction +sleep 6 + # Submit governance proposal for software-upgrade to v1 echo ">>> Submitting proposal for software-upgrade" -$BINARY tx gov submit-proposal software-upgrade "v1" --title "Software Upgrade to v1" --description "This software-upgrade v1 introduces qvesting, token factory and authx module" --upgrade-height $UPGRADE_HEIGHT --deposit 100uqsr --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --node $RPC +$BINARY tx gov submit-proposal software-upgrade "v1" --title "Software Upgrade to v1" --description "This software-upgrade v1 introduces qvesting, token factory and authz module" --upgrade-height $UPGRADE_HEIGHT --deposit 100uqsr --from $ACCOUNT_NAME --keyring-backend test -y --output json --chain-id $CHAIN_ID --fees 10000uqsr --gas 7000000 --node $RPC -sleep 5 +sleep 20 echo ">>> Voting yes to proposal" $BINARY tx gov vote 1 yes --from my_treasury --chain-id $CHAIN_ID --keyring-backend test -y @@ -49,4 +52,4 @@ BINARY=quasarnoded HOME_QSR=$HOME/.quasarnode echo "starting with new binary" -$BINARY start --home $HOME_QSR >>./logs/quasar.log 2>&1 +$BINARY start --home $HOME_QSR >>./logs/quasar.log 2>&1 & From 281438f86e839fb9d8888739d2d2871d81b597b4 Mon Sep 17 00:00:00 2001 From: Arham Chordia <43543921+arhamchordia@users.noreply.github.com> Date: Tue, 8 Aug 2023 22:03:17 +0530 Subject: [PATCH 7/7] Adding closing command in testing script. --- demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh b/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh index d5e6ae297..3d468e2c5 100644 --- a/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh +++ b/demos/upgrade-handler/v1.0.0/test_upgrade_with_contracts.sh @@ -66,3 +66,8 @@ fi ## wait is added so that the all the processes are not killed. ## please perform all the other queries after the announcement of test finished in order to check all the actions are working properly wait + +# Run these commands once you have finished with the tests +#pkill quasarnoded +#pkill osmosisd +#pkill rly \ No newline at end of file