From 2573951d2c07b45f1fdf9f016e7ff1faa36be7c6 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Thu, 20 Apr 2023 15:51:21 +0700 Subject: [PATCH 01/24] add liquidity module for future removal --- app/keepers/keepers.go | 4 +- app/keepers/keys.go | 2 +- app/modules.go | 4 +- go.mod | 9 +- go.sum | 2 - .../liquidity/v1beta1/genesis.proto | 27 + .../liquidity/v1beta1/liquidity.proto | 424 ++ .../tendermint/liquidity/v1beta1/query.proto | 508 ++ proto/tendermint/liquidity/v1beta1/tx.proto | 211 + third_party/proto/confio/proofs.proto | 234 + third_party/proto/cosmos_proto/coin.proto | 40 + .../proto/cosmos_proto/pagination.proto | 50 + third_party/proto/google/protobuf/any.proto | 3 - .../protoc-gen-openapiv2/options/BUILD.bazel | 38 + .../options/annotations.pb.go | 241 + .../options/annotations.proto | 44 + .../options/openapiv2.pb.go | 2790 +++++++++ .../options/openapiv2.proto | 645 +++ third_party/proto/tendermint/abci/types.proto | 407 ++ .../proto/tendermint/crypto/keys.proto | 17 + .../proto/tendermint/crypto/proof.proto | 41 + .../proto/tendermint/libs/bits/types.proto | 9 + third_party/proto/tendermint/p2p/types.proto | 34 + .../proto/tendermint/types/block.proto | 15 + .../proto/tendermint/types/evidence.proto | 38 + .../proto/tendermint/types/params.proto | 80 + .../proto/tendermint/types/types.proto | 157 + .../proto/tendermint/types/validator.proto | 25 + .../proto/tendermint/version/types.proto | 24 + x/liquidity/abci.go | 25 + x/liquidity/client/cli/cli_test.go | 1597 ++++++ x/liquidity/client/cli/flags.go | 21 + x/liquidity/client/cli/query.go | 577 ++ x/liquidity/client/cli/tx.go | 336 ++ x/liquidity/client/testutil/cli_helpers.go | 144 + x/liquidity/doc.go | 16 + x/liquidity/genesis.go | 18 + x/liquidity/genesis_test.go | 71 + x/liquidity/handler.go | 36 + x/liquidity/handler_test.go | 297 + x/liquidity/keeper/batch.go | 289 + x/liquidity/keeper/batch_test.go | 1243 +++++ x/liquidity/keeper/common_test.go | 94 + x/liquidity/keeper/genesis.go | 61 + x/liquidity/keeper/genesis_test.go | 138 + x/liquidity/keeper/grpc_query.go | 327 ++ x/liquidity/keeper/grpc_query_test.go | 497 ++ x/liquidity/keeper/invariants.go | 378 ++ x/liquidity/keeper/invariants_test.go | 144 + x/liquidity/keeper/keeper.go | 69 + x/liquidity/keeper/keeper_test.go | 64 + x/liquidity/keeper/liquidity_pool.go | 915 +++ x/liquidity/keeper/liquidity_pool_test.go | 1324 +++++ x/liquidity/keeper/migration.go | 22 + x/liquidity/keeper/msg_server.go | 167 + x/liquidity/keeper/msg_server_test.go | 431 ++ x/liquidity/keeper/querier.go | 64 + x/liquidity/keeper/querier_test.go | 128 + x/liquidity/keeper/store.go | 600 ++ x/liquidity/keeper/store_test.go | 355 ++ x/liquidity/keeper/swap.go | 147 + x/liquidity/keeper/swap_test.go | 357 ++ x/liquidity/legacy/v042/keys.go | 32 + x/liquidity/legacy/v043/helpers.go | 36 + x/liquidity/legacy/v043/store.go | 25 + x/liquidity/legacy/v043/store_test.go | 81 + x/liquidity/module.go | 205 + x/liquidity/module_test.go | 25 + x/liquidity/simulation/decoder.go | 56 + x/liquidity/simulation/decoder_test.go | 98 + x/liquidity/simulation/genesis.go | 167 + x/liquidity/simulation/genesis_test.go | 84 + x/liquidity/simulation/operations.go | 387 ++ x/liquidity/simulation/operations_test.go | 249 + x/liquidity/simulation/operations_utils.go | 117 + x/liquidity/simulation/params.go | 55 + x/liquidity/simulation/params_test.go | 41 + x/liquidity/spec/01_concepts.md | 67 + x/liquidity/spec/02_state.md | 123 + x/liquidity/spec/03_state_transitions.md | 250 + x/liquidity/spec/04_messages.md | 104 + x/liquidity/spec/05_begin_block.md | 18 + x/liquidity/spec/06_end_block.md | 32 + x/liquidity/spec/07_events.md | 118 + x/liquidity/spec/08_params.md | 92 + x/liquidity/spec/README.md | 27 + x/liquidity/types/codec.go | 48 + x/liquidity/types/errors.go | 50 + x/liquidity/types/events.go | 53 + x/liquidity/types/expected_keepers.go | 33 + x/liquidity/types/genesis.go | 44 + x/liquidity/types/genesis.pb.go | 856 +++ x/liquidity/types/genesis_test.go | 152 + x/liquidity/types/keys.go | 109 + x/liquidity/types/keys_test.go | 74 + x/liquidity/types/liquidity.pb.go | 3439 ++++++++++++ x/liquidity/types/liquidity_pool.go | 190 + x/liquidity/types/liquidity_pool_test.go | 133 + x/liquidity/types/msgs.go | 230 + x/liquidity/types/msgs_test.go | 406 ++ x/liquidity/types/params.go | 318 ++ x/liquidity/types/params_internal_test.go | 26 + x/liquidity/types/params_test.go | 243 + x/liquidity/types/querier.go | 33 + x/liquidity/types/query.go | 4 + x/liquidity/types/query.pb.go | 4963 +++++++++++++++++ x/liquidity/types/query.pb.gw.go | 1366 +++++ x/liquidity/types/swap.go | 617 ++ x/liquidity/types/swap_test.go | 680 +++ x/liquidity/types/tx.pb.go | 2069 +++++++ x/liquidity/types/utils.go | 124 + x/liquidity/types/utils_test.go | 340 ++ 112 files changed, 36149 insertions(+), 15 deletions(-) create mode 100644 proto/tendermint/liquidity/v1beta1/genesis.proto create mode 100644 proto/tendermint/liquidity/v1beta1/liquidity.proto create mode 100644 proto/tendermint/liquidity/v1beta1/query.proto create mode 100644 proto/tendermint/liquidity/v1beta1/tx.proto create mode 100644 third_party/proto/confio/proofs.proto create mode 100644 third_party/proto/cosmos_proto/coin.proto create mode 100644 third_party/proto/cosmos_proto/pagination.proto create mode 100644 third_party/proto/protoc-gen-openapiv2/options/BUILD.bazel create mode 100644 third_party/proto/protoc-gen-openapiv2/options/annotations.pb.go create mode 100644 third_party/proto/protoc-gen-openapiv2/options/annotations.proto create mode 100644 third_party/proto/protoc-gen-openapiv2/options/openapiv2.pb.go create mode 100644 third_party/proto/protoc-gen-openapiv2/options/openapiv2.proto create mode 100644 third_party/proto/tendermint/abci/types.proto create mode 100644 third_party/proto/tendermint/crypto/keys.proto create mode 100644 third_party/proto/tendermint/crypto/proof.proto create mode 100644 third_party/proto/tendermint/libs/bits/types.proto create mode 100644 third_party/proto/tendermint/p2p/types.proto create mode 100644 third_party/proto/tendermint/types/block.proto create mode 100644 third_party/proto/tendermint/types/evidence.proto create mode 100644 third_party/proto/tendermint/types/params.proto create mode 100644 third_party/proto/tendermint/types/types.proto create mode 100644 third_party/proto/tendermint/types/validator.proto create mode 100644 third_party/proto/tendermint/version/types.proto create mode 100644 x/liquidity/abci.go create mode 100644 x/liquidity/client/cli/cli_test.go create mode 100644 x/liquidity/client/cli/flags.go create mode 100644 x/liquidity/client/cli/query.go create mode 100644 x/liquidity/client/cli/tx.go create mode 100644 x/liquidity/client/testutil/cli_helpers.go create mode 100644 x/liquidity/doc.go create mode 100644 x/liquidity/genesis.go create mode 100644 x/liquidity/genesis_test.go create mode 100644 x/liquidity/handler.go create mode 100644 x/liquidity/handler_test.go create mode 100644 x/liquidity/keeper/batch.go create mode 100644 x/liquidity/keeper/batch_test.go create mode 100644 x/liquidity/keeper/common_test.go create mode 100644 x/liquidity/keeper/genesis.go create mode 100644 x/liquidity/keeper/genesis_test.go create mode 100644 x/liquidity/keeper/grpc_query.go create mode 100644 x/liquidity/keeper/grpc_query_test.go create mode 100644 x/liquidity/keeper/invariants.go create mode 100644 x/liquidity/keeper/invariants_test.go create mode 100644 x/liquidity/keeper/keeper.go create mode 100644 x/liquidity/keeper/keeper_test.go create mode 100644 x/liquidity/keeper/liquidity_pool.go create mode 100644 x/liquidity/keeper/liquidity_pool_test.go create mode 100644 x/liquidity/keeper/migration.go create mode 100644 x/liquidity/keeper/msg_server.go create mode 100644 x/liquidity/keeper/msg_server_test.go create mode 100644 x/liquidity/keeper/querier.go create mode 100644 x/liquidity/keeper/querier_test.go create mode 100644 x/liquidity/keeper/store.go create mode 100644 x/liquidity/keeper/store_test.go create mode 100644 x/liquidity/keeper/swap.go create mode 100644 x/liquidity/keeper/swap_test.go create mode 100644 x/liquidity/legacy/v042/keys.go create mode 100644 x/liquidity/legacy/v043/helpers.go create mode 100644 x/liquidity/legacy/v043/store.go create mode 100644 x/liquidity/legacy/v043/store_test.go create mode 100644 x/liquidity/module.go create mode 100644 x/liquidity/module_test.go create mode 100644 x/liquidity/simulation/decoder.go create mode 100644 x/liquidity/simulation/decoder_test.go create mode 100644 x/liquidity/simulation/genesis.go create mode 100644 x/liquidity/simulation/genesis_test.go create mode 100644 x/liquidity/simulation/operations.go create mode 100644 x/liquidity/simulation/operations_test.go create mode 100644 x/liquidity/simulation/operations_utils.go create mode 100644 x/liquidity/simulation/params.go create mode 100644 x/liquidity/simulation/params_test.go create mode 100644 x/liquidity/spec/01_concepts.md create mode 100644 x/liquidity/spec/02_state.md create mode 100644 x/liquidity/spec/03_state_transitions.md create mode 100644 x/liquidity/spec/04_messages.md create mode 100644 x/liquidity/spec/05_begin_block.md create mode 100644 x/liquidity/spec/06_end_block.md create mode 100644 x/liquidity/spec/07_events.md create mode 100644 x/liquidity/spec/08_params.md create mode 100644 x/liquidity/spec/README.md create mode 100644 x/liquidity/types/codec.go create mode 100644 x/liquidity/types/errors.go create mode 100644 x/liquidity/types/events.go create mode 100644 x/liquidity/types/expected_keepers.go create mode 100644 x/liquidity/types/genesis.go create mode 100644 x/liquidity/types/genesis.pb.go create mode 100644 x/liquidity/types/genesis_test.go create mode 100644 x/liquidity/types/keys.go create mode 100644 x/liquidity/types/keys_test.go create mode 100644 x/liquidity/types/liquidity.pb.go create mode 100644 x/liquidity/types/liquidity_pool.go create mode 100644 x/liquidity/types/liquidity_pool_test.go create mode 100644 x/liquidity/types/msgs.go create mode 100644 x/liquidity/types/msgs_test.go create mode 100644 x/liquidity/types/params.go create mode 100644 x/liquidity/types/params_internal_test.go create mode 100644 x/liquidity/types/params_test.go create mode 100644 x/liquidity/types/querier.go create mode 100644 x/liquidity/types/query.go create mode 100644 x/liquidity/types/query.pb.go create mode 100644 x/liquidity/types/query.pb.gw.go create mode 100644 x/liquidity/types/swap.go create mode 100644 x/liquidity/types/swap_test.go create mode 100644 x/liquidity/types/tx.pb.go create mode 100644 x/liquidity/types/utils.go create mode 100644 x/liquidity/types/utils_test.go diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index ed7fd888550..cdd8b6ad255 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -42,6 +42,8 @@ import ( upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/cosmos/gaia/v9/x/globalfee" + liquiditykeeper "github.com/cosmos/gaia/v9/x/liquidity/keeper" + liquiditytypes "github.com/cosmos/gaia/v9/x/liquidity/types" ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" icahost "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host" icahostkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" @@ -56,8 +58,6 @@ import ( ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" ibcprovider "github.com/cosmos/interchain-security/x/ccv/provider" ibcproviderkeeper "github.com/cosmos/interchain-security/x/ccv/provider/keeper" - liquiditykeeper "github.com/gravity-devs/liquidity/x/liquidity/keeper" - liquiditytypes "github.com/gravity-devs/liquidity/x/liquidity/types" "github.com/strangelove-ventures/packet-forward-middleware/v4/router" routerkeeper "github.com/strangelove-ventures/packet-forward-middleware/v4/router/keeper" routertypes "github.com/strangelove-ventures/packet-forward-middleware/v4/router/types" diff --git a/app/keepers/keys.go b/app/keepers/keys.go index 80e338b532d..ae2ff599e41 100644 --- a/app/keepers/keys.go +++ b/app/keepers/keys.go @@ -16,11 +16,11 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + liquiditytypes "github.com/cosmos/gaia/v9/x/liquidity/types" icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" - liquiditytypes "github.com/gravity-devs/liquidity/x/liquidity/types" routertypes "github.com/strangelove-ventures/packet-forward-middleware/v4/router/types" ) diff --git a/app/modules.go b/app/modules.go index a8d24548aaa..a41d8afe7ef 100644 --- a/app/modules.go +++ b/app/modules.go @@ -38,6 +38,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/upgrade" upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/cosmos/gaia/v9/x/liquidity" + liquiditytypes "github.com/cosmos/gaia/v9/x/liquidity/types" ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" "github.com/cosmos/ibc-go/v4/modules/apps/transfer" @@ -48,8 +50,6 @@ import ( ibcprovider "github.com/cosmos/interchain-security/x/ccv/provider" ibcproviderclient "github.com/cosmos/interchain-security/x/ccv/provider/client" providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" - "github.com/gravity-devs/liquidity/x/liquidity" - liquiditytypes "github.com/gravity-devs/liquidity/x/liquidity/types" "github.com/strangelove-ventures/packet-forward-middleware/v4/router" routertypes "github.com/strangelove-ventures/packet-forward-middleware/v4/router/types" diff --git a/go.mod b/go.mod index 8d223972b6b..14cb373db0b 100644 --- a/go.mod +++ b/go.mod @@ -11,13 +11,12 @@ require ( github.com/golang/protobuf v1.5.3 github.com/golangci/golangci-lint v1.52.2 github.com/gorilla/mux v1.8.0 - github.com/gravity-devs/liquidity v1.5.3 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/pkg/errors v0.9.1 // indirect github.com/rakyll/statik v0.1.7 github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.7.0 - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.15.0 github.com/strangelove-ventures/packet-forward-middleware/v4 v4.0.4 github.com/stretchr/testify v1.8.2 @@ -29,7 +28,10 @@ require ( require ( cosmossdk.io/math v1.0.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.2 github.com/ory/dockertest/v3 v3.9.1 + google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 + gopkg.in/yaml.v2 v2.4.0 ) require ( @@ -155,7 +157,6 @@ require ( github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect @@ -294,9 +295,7 @@ require ( golang.org/x/term v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect golang.org/x/tools v0.7.0 // indirect - google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.4.3 // indirect mvdan.cc/gofumpt v0.4.0 // indirect diff --git a/go.sum b/go.sum index c902c04b5f3..ba38006746a 100644 --- a/go.sum +++ b/go.sum @@ -1638,8 +1638,6 @@ github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Rep github.com/gotestyourself/gotestyourself v1.4.0/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= -github.com/gravity-devs/liquidity v1.5.3 h1:QbMHk1q+dzlM76Zv3vxaHhq4lBdhaelB0g7NmLbsv2Q= -github.com/gravity-devs/liquidity v1.5.3/go.mod h1:ULtNk738lNb1Kh31larCNxZ7IK21TeKZmNzS/OkE0hw= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= diff --git a/proto/tendermint/liquidity/v1beta1/genesis.proto b/proto/tendermint/liquidity/v1beta1/genesis.proto new file mode 100644 index 00000000000..cf66cee3698 --- /dev/null +++ b/proto/tendermint/liquidity/v1beta1/genesis.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; +package tendermint.liquidity.v1beta1; + +import "tendermint/liquidity/v1beta1/liquidity.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/gaia/v9/x/liquidity/types"; + +// records the state of each pool after genesis export or import, used to check variables +message PoolRecord { + Pool pool = 1 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"pool\""]; + PoolMetadata pool_metadata = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"pool_metadata\""]; + PoolBatch pool_batch = 3 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"pool_batch\""]; + repeated DepositMsgState deposit_msg_states = 4 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"deposit_msg_states\""]; + repeated WithdrawMsgState withdraw_msg_states = 5 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"withdraw_msg_states\""]; + repeated SwapMsgState swap_msg_states = 6 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"swap_msg_states\""]; +} + +// GenesisState defines the liquidity module's genesis state. +message GenesisState { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // params defines all the parameters for the liquidity module. + Params params = 1 [(gogoproto.nullable) = false]; + repeated PoolRecord pool_records = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"pools\""]; +} diff --git a/proto/tendermint/liquidity/v1beta1/liquidity.proto b/proto/tendermint/liquidity/v1beta1/liquidity.proto new file mode 100644 index 00000000000..502248d6a3a --- /dev/null +++ b/proto/tendermint/liquidity/v1beta1/liquidity.proto @@ -0,0 +1,424 @@ +syntax = "proto3"; +package tendermint.liquidity.v1beta1; + +import "tendermint/liquidity/v1beta1/tx.proto"; +import "gogoproto/gogo.proto"; +import "cosmos_proto/coin.proto"; +import "protoc-gen-openapiv2/options/annotations.proto"; + +option go_package = "github.com/cosmos/gaia/v9/x/liquidity/types"; +option (gogoproto.goproto_getters_all) = false; + +// Structure for the pool type to distinguish the characteristics of the reserve pools. +message PoolType { + option (gogoproto.equal) = true; + + // This is the id of the pool_type that is used as pool_type_id for pool creation. + // In this version, only pool-type-id 1 is supported. + // {"id":1,"name":"ConstantProductLiquidityPool","min_reserve_coin_num":2,"max_reserve_coin_num":2,"description":""} + uint32 id = 1 [(gogoproto.moretags) = "yaml:\"id\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint32" + }]; + + // name of the pool type. + string name = 2 [(gogoproto.moretags) = "yaml:\"name\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"ConstantProductLiquidityPool\"", + }]; + + // minimum number of reserveCoins for LiquidityPoolType, only 2 reserve coins are supported. + uint32 min_reserve_coin_num = 3 [(gogoproto.moretags) = "yaml:\"min_reserve_coin_num\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"2\"", + format: "uint32" + }]; + + // maximum number of reserveCoins for LiquidityPoolType, only 2 reserve coins are supported. + uint32 max_reserve_coin_num = 4 [(gogoproto.moretags) = "yaml:\"max_reserve_coin_num\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"2\"", + format: "uint32" + }]; + + // description of the pool type. + string description = 5 [(gogoproto.moretags) = "yaml:\"description\""]; +} + +// Params defines the parameters for the liquidity module. +message Params { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + // list of available pool types + repeated PoolType pool_types = 1 [ + (gogoproto.moretags) = "yaml:\"pool_types\"", + (gogoproto.nullable) = false + ]; + + // Minimum number of coins to be deposited to the liquidity pool on pool creation. + string min_init_deposit_amount = 2 [ + (gogoproto.moretags) = "yaml:\"min_init_deposit_amount\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000000\"", + format: "sdk.Int" + }]; + + // Initial mint amount of pool coins upon pool creation. + string init_pool_coin_mint_amount = 3 [ + (gogoproto.moretags) = "yaml:\"init_pool_coin_mint_amount\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000000\"", + format: "sdk.Int" + }]; + + // Limit the size of each liquidity pool to minimize risk. In development, set to 0 for no limit. In production, set a limit. + string max_reserve_coin_amount = 4 [ + (gogoproto.moretags) = "yaml:\"max_reserve_coin_amount\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000000000000\"", + format: "sdk.Int" + }]; + + // Fee paid to create a Liquidity Pool. Set a fee to prevent spamming. + repeated cosmos.base.v1beta1.Coin pool_creation_fee = 5 [ + (gogoproto.moretags) = "yaml:\"pool_creation_fee\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "[{\"denom\": \"uatom\", \"amount\": \"100000000\"}]", + format: "sdk.Coins" + } + ]; + + // Swap fee rate for every executed swap. + string swap_fee_rate = 6 [ + (gogoproto.moretags) = "yaml:\"swap_fee_rate\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"0.003\"", + format: "sdk.Dec" + }]; + + // Reserve coin withdrawal with less proportion by withdrawFeeRate. + string withdraw_fee_rate = 7 [ + (gogoproto.moretags) = "yaml:\"withdraw_fee_rate\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"0.003\"", + format: "sdk.Dec" + }]; + + // Maximum ratio of reserve coins that can be ordered at a swap order. + string max_order_amount_ratio = 8 [ + (gogoproto.moretags) = "yaml:\"max_order_amount_ratio\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"0.003\"", + format: "sdk.Dec" + }]; + + // The smallest unit batch height for every liquidity pool. + uint32 unit_batch_height = 9 [ + (gogoproto.moretags) = "yaml:\"unit_batch_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint32" + }]; + + // Circuit breaker enables or disables transaction messages in liquidity module. + bool circuit_breaker_enabled = 10 [ + (gogoproto.moretags) = "yaml:\"circuit_breaker_enabled\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"false\"", + format: "bool" + }]; +} + +// Pool defines the liquidity pool that contains pool information. +message Pool { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = true; + + // id of the pool + uint64 id = 1 [(gogoproto.moretags) = "yaml:\"id\"", (gogoproto.jsontag) = "id", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // id of the pool_type + uint32 type_id = 2 [(gogoproto.moretags) = "yaml:\"type_id\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint32" + }]; + + // denoms of reserve coin pair of the pool + repeated string reserve_coin_denoms = 3 [(gogoproto.moretags) = "yaml:\"reserve_coin_denoms\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "[\"denomX\",\"denomY\"]" + }]; + + // reserve account address of the pool + string reserve_account_address = 4 [(gogoproto.moretags) = "yaml:\"reserve_account_address\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"cosmos16ddqestwukv0jzcyfn3fdfq9h2wrs83cr4rfm3\"", + format: "sdk.AccAddress" + }]; + + // denom of pool coin of the pool + string pool_coin_denom = 5 [(gogoproto.moretags) = "yaml:\"pool_coin_denom\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4\"", + }]; +} + +// Metadata for the state of each pool for invariant checking after genesis export or import. +message PoolMetadata { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = true; + + // id of the pool + uint64 pool_id = 1 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // pool coin issued at the pool + cosmos.base.v1beta1.Coin pool_coin_total_supply = 2 [ + (gogoproto.moretags) = "yaml:\"pool_coin_total_supply\"", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4\", \"amount\": \"1000000\"}", + format: "sdk.Coin" + }]; + + // reserve coins deposited in the pool + repeated cosmos.base.v1beta1.Coin reserve_coins = 3 [ + (gogoproto.moretags) = "yaml:\"reserve_coins\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "[{\"denom\": \"denomX\", \"amount\": \"1000000\"}, {\"denom\": \"denomY\", \"amount\": \"2000000\"}]", + format: "sdk.Coins" + }]; +} + +// PoolBatch defines the batch or batches of a given liquidity pool that contains indexes of deposit, withdraw, and swap messages. +// Index param increments by 1 if the pool id is same. +message PoolBatch { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = true; + + // id of the pool + uint64 pool_id = 1 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // index of this batch + uint64 index = 2 [(gogoproto.moretags) = "yaml:\"index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // height where this batch is started + int64 begin_height = 3 [(gogoproto.moretags) = "yaml:\"begin_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + }]; + + // last index of DepositMsgStates + uint64 deposit_msg_index = 4 [(gogoproto.moretags) = "yaml:\"deposit_msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // last index of WithdrawMsgStates + uint64 withdraw_msg_index = 5 [(gogoproto.moretags) = "yaml:\"withdraw_msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // last index of SwapMsgStates + uint64 swap_msg_index = 6 [(gogoproto.moretags) = "yaml:\"swap_msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // true if executed, false if not executed + bool executed = 7 [(gogoproto.moretags) = "yaml:\"executed\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; +} + +// DepositMsgState defines the state of deposit message that contains state information as it is processed in the next batch or batches. +message DepositMsgState { + + // height where this message is appended to the batch + int64 msg_height = 1 [(gogoproto.moretags) = "yaml:\"msg_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + }]; + + // index of this deposit message in this liquidity pool + uint64 msg_index = 2 [(gogoproto.moretags) = "yaml:\"msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // true if executed on this batch, false if not executed + bool executed = 3 [(gogoproto.moretags) = "yaml:\"executed\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; + + // true if executed successfully on this batch, false if failed + bool succeeded = 4 [(gogoproto.moretags) = "yaml:\"succeeded\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; + + // true if ready to be deleted on kvstore, false if not ready to be deleted + bool to_be_deleted = 5 [(gogoproto.moretags) = "yaml:\"to_be_deleted\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; + + // MsgDepositWithinBatch + MsgDepositWithinBatch msg = 6 [(gogoproto.moretags) = "yaml:\"msg\""]; +} + +// WithdrawMsgState defines the state of the withdraw message that contains state information as the message is processed in the next batch or batches. +message WithdrawMsgState { + + // height where this message is appended to the batch + int64 msg_height = 1 [(gogoproto.moretags) = "yaml:\"msg_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + }]; + + // index of this withdraw message in this liquidity pool + uint64 msg_index = 2 [(gogoproto.moretags) = "yaml:\"msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // true if executed on this batch, false if not executed + bool executed = 3 [(gogoproto.moretags) = "yaml:\"executed\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; + + // true if executed successfully on this batch, false if failed + bool succeeded = 4 [(gogoproto.moretags) = "yaml:\"succeeded\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; + + // true if ready to be deleted on kvstore, false if not ready to be deleted + bool to_be_deleted = 5 [(gogoproto.moretags) = "yaml:\"to_be_deleted\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; + + // MsgWithdrawWithinBatch + MsgWithdrawWithinBatch msg = 6 [(gogoproto.moretags) = "yaml:\"msg\""]; +} + +// SwapMsgState defines the state of the swap message that contains state information as the message is processed in the next batch or batches. +message SwapMsgState { + + // height where this message is appended to the batch + int64 msg_height = 1 [(gogoproto.moretags) = "yaml:\"msg_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + }]; + + // index of this swap message in this liquidity pool + uint64 msg_index = 2 [(gogoproto.moretags) = "yaml:\"msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // true if executed on this batch, false if not executed + bool executed = 3 [(gogoproto.moretags) = "yaml:\"executed\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; + + // true if executed successfully on this batch, false if failed + bool succeeded = 4 [(gogoproto.moretags) = "yaml:\"succeeded\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; + + // true if ready to be deleted on kvstore, false if not ready to be deleted + bool to_be_deleted = 5 [(gogoproto.moretags) = "yaml:\"to_be_deleted\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true", + }]; + + // swap orders are cancelled when current height is equal to or higher than ExpiryHeight + int64 order_expiry_height = 6 [(gogoproto.moretags) = "yaml:\"order_expiry_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + }]; + + // offer coin exchanged until now + cosmos.base.v1beta1.Coin exchanged_offer_coin = 7 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"exchanged_offer_coin\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"denomX\", \"amount\": \"600000\"}", + format: "sdk.Coin" + }]; + + // offer coin currently remaining to be exchanged + cosmos.base.v1beta1.Coin remaining_offer_coin = 8 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"remaining_offer_coin\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"denomX\", \"amount\": \"400000\"}", + format: "sdk.Coin" + }]; + + // reserve fee for pays fee in half offer coin + cosmos.base.v1beta1.Coin reserved_offer_coin_fee = 9 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"reserved_offer_coin_fee\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"denomX\", \"amount\": \"5000\"}", + format: "sdk.Coin" + } + ]; + + // MsgSwapWithinBatch + MsgSwapWithinBatch msg = 10 [(gogoproto.moretags) = "yaml:\"msg\""]; +} diff --git a/proto/tendermint/liquidity/v1beta1/query.proto b/proto/tendermint/liquidity/v1beta1/query.proto new file mode 100644 index 00000000000..9eeb66620de --- /dev/null +++ b/proto/tendermint/liquidity/v1beta1/query.proto @@ -0,0 +1,508 @@ +syntax = "proto3"; +package tendermint.liquidity.v1beta1; + +import "gogoproto/gogo.proto"; +import "tendermint/liquidity/v1beta1/liquidity.proto"; +import "google/api/annotations.proto"; +import "cosmos_proto/pagination.proto"; +import "protoc-gen-openapiv2/options/annotations.proto"; + +option go_package = "github.com/cosmos/gaia/v9/x/liquidity/types"; + +// Query defines the gRPC query service for the liquidity module. +service Query { + // Get existing liquidity pools. + rpc LiquidityPools (QueryLiquidityPoolsRequest) returns (QueryLiquidityPoolsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns a list of all liquidity pools with pagination result."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = There are no pools present.: key not found","details":[]}' + } + } + } + }; + } + + // Get specific liquidity pool. + rpc LiquidityPool (QueryLiquidityPoolRequest) returns (QueryLiquidityPoolResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the liquidity pool that corresponds to the pool_id."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get specific liquidity pool corresponding to the pool_coin_denom. + rpc LiquidityPoolByPoolCoinDenom (QueryLiquidityPoolByPoolCoinDenomRequest) returns (QueryLiquidityPoolResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/pool_coin_denom/{pool_coin_denom}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "It returns the liquidity pool corresponding to the pool_coin_denom."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = the liquidity pool corresponding to the pool_coin_denom doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "404" + value: { + description: "Not Found" + examples: { + key: "application/json" + value: '{"code":5,"message":"rpc error: code = NotFound desc = liquidity pool with pool coin denom xx doesn\'t exist: key not found","details":[]}' + } + } + } + }; + } + + + // Get specific liquidity pool corresponding to the reserve account. + rpc LiquidityPoolByReserveAcc (QueryLiquidityPoolByReserveAccRequest) returns (QueryLiquidityPoolResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/reserve_acc/{reserve_acc}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "It returns the liquidity pool corresponding to the reserve account."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = the liquidity pool corresponding to the reserve account doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "404" + value: { + description: "Not Found" + examples: { + key: "application/json" + value: '{"code":5,"message":"rpc error: code = NotFound desc = the reserve account address xx is not valid: key not found","details":[]}' + } + } + } + }; + } + + // Get the pool's current batch. + rpc LiquidityPoolBatch (QueryLiquidityPoolBatchRequest) returns (QueryLiquidityPoolBatchResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the current batch of the pool that corresponds to the pool_id."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get all swap messages in the pool's current batch. + rpc PoolBatchSwapMsgs(QueryPoolBatchSwapMsgsRequest) returns (QueryPoolBatchSwapMsgsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/swaps"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns a list of all swap messages in the current batch of the pool with pagination result."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get a specific swap message in the pool's current batch. + rpc PoolBatchSwapMsg(QueryPoolBatchSwapMsgRequest) returns (QueryPoolBatchSwapMsgResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/swaps/{msg_index}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the swap message that corresponds to the msg_index in the pool's current batch"; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"root":{"code":2,"details":[],"message":"rpc error: code = NotFound desc = the msg given msg_index 1 doesn\'t exist or deleted: key not found"}}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: msg_index, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get all deposit messages in the pool's current batch. + rpc PoolBatchDepositMsgs(QueryPoolBatchDepositMsgsRequest) returns (QueryPoolBatchDepositMsgsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/deposits"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns a list of all deposit messages in the current batch of the pool with pagination result."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + + }; + } + + // Get a specific deposit message in the pool's current batch. + rpc PoolBatchDepositMsg(QueryPoolBatchDepositMsgRequest) returns (QueryPoolBatchDepositMsgResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/deposits/{msg_index}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the deposit message that corresponds to the msg_index in the pool's current batch."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"root":{"code":2,"details":[],"message":"rpc error: code = NotFound desc = the msg given msg_index 1 doesn\'t exist or deleted: key not found"}}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: msg_index, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get all withdraw messages in the pool's current batch. + rpc PoolBatchWithdrawMsgs(QueryPoolBatchWithdrawMsgsRequest) returns (QueryPoolBatchWithdrawMsgsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/withdraws"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns a list of all withdraw messages in the current batch of the pool with pagination result."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + + }; + } + + // Get a specific withdraw message in the pool's current batch. + rpc PoolBatchWithdrawMsg(QueryPoolBatchWithdrawMsgRequest) returns (QueryPoolBatchWithdrawMsgResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/withdraws/{msg_index}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the withdraw message that corresponds to the msg_index in the pool's current batch."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"root":{"code":2,"details":[],"message":"rpc error: code = NotFound desc = the msg given msg_index 1 doesn\'t exist or deleted: key not found"}}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: msg_index, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get all parameters of the liquidity module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/params"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns all parameters of the liquidity module."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/x/liquidity/spec/08_params.md"; + description: "Find out more about the params"; + } + }; + } +} + +// the request type for the QueryLiquidityPool RPC method. requestable specified pool_id. +message QueryLiquidityPoolRequest { + uint64 pool_id = 1; +} + +// the response type for the QueryLiquidityPoolResponse RPC method. Returns the liquidity pool that corresponds to the requested pool_id. +message QueryLiquidityPoolResponse { + Pool pool = 1 [(gogoproto.nullable) = false]; +} + +// the request type for the QueryLiquidityByPoolCoinDenomPool RPC method. Requestable specified pool_coin_denom. +message QueryLiquidityPoolByPoolCoinDenomRequest { + string pool_coin_denom = 1; +} + +// the request type for the QueryLiquidityByReserveAcc RPC method. Requestable specified reserve_acc. +message QueryLiquidityPoolByReserveAccRequest { + string reserve_acc = 1; +} + +// the request type for the QueryLiquidityPoolBatch RPC method. requestable including specified pool_id. +message QueryLiquidityPoolBatchRequest { + // id of the target pool for query + uint64 pool_id = 1; +} + +// the response type for the QueryLiquidityPoolBatchResponse RPC method. Returns the liquidity pool batch that corresponds to the requested pool_id. +message QueryLiquidityPoolBatchResponse { + PoolBatch batch = 1 [(gogoproto.nullable) = false]; +} + +// the request type for the QueryLiquidityPools RPC method. Requestable including pagination offset, limit, key. +message QueryLiquidityPoolsRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// the response type for the QueryLiquidityPoolsResponse RPC method. This includes a list of all existing liquidity pools and paging results that contain next_key and total count. +message QueryLiquidityPoolsResponse { + repeated Pool pools = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. not working on this version. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryParamsRequest is request type for the QueryParams RPC method. +message QueryParamsRequest {} + +// the response type for the QueryParamsResponse RPC method. This includes current parameter of the liquidity module. +message QueryParamsResponse { + // params holds all the parameters of this module. + Params params = 1 [(gogoproto.nullable) = false]; +} + +// the request type for the QueryPoolBatchSwapMsgs RPC method. Requestable including specified pool_id and pagination offset, limit, key. +message QueryPoolBatchSwapMsgsRequest { + // id of the target pool for query + uint64 pool_id = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// the request type for the QueryPoolBatchSwap RPC method. Requestable including specified pool_id and msg_index. +message QueryPoolBatchSwapMsgRequest { + // id of the target pool for query + uint64 pool_id = 1; + // target msg_index of the pool + uint64 msg_index = 2; +} + +// the response type for the QueryPoolBatchSwapMsgs RPC method. This includes list of all currently existing swap messages of the batch and paging results that contain next_key and total count. +message QueryPoolBatchSwapMsgsResponse { + repeated SwapMsgState swaps = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. not working on this version. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// the response type for the QueryPoolBatchSwapMsg RPC method. This includes a batch swap message of the batch. +message QueryPoolBatchSwapMsgResponse { + SwapMsgState swap = 1 [(gogoproto.nullable) = false]; +} + +// the request type for the QueryPoolBatchDeposit RPC method. Requestable including specified pool_id and pagination offset, limit, key. +message QueryPoolBatchDepositMsgsRequest { + // id of the target pool for query + uint64 pool_id = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// the request type for the QueryPoolBatchDeposit RPC method. requestable including specified pool_id and msg_index. +message QueryPoolBatchDepositMsgRequest { + // id of the target pool for query + uint64 pool_id = 1; + // target msg_index of the pool + uint64 msg_index = 2; +} + +// the response type for the QueryPoolBatchDeposit RPC method. This includes a list of all currently existing deposit messages of the batch and paging results that contain next_key and total count. +message QueryPoolBatchDepositMsgsResponse { + repeated DepositMsgState deposits = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. not working on this version. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// the response type for the QueryPoolBatchDepositMsg RPC method. This includes a batch swap message of the batch. +message QueryPoolBatchDepositMsgResponse { + DepositMsgState deposit = 1 [(gogoproto.nullable) = false]; +} + + +// the request type for the QueryPoolBatchWithdraw RPC method. Requestable including specified pool_id and pagination offset, limit, key. +message QueryPoolBatchWithdrawMsgsRequest { + // id of the target pool for query + uint64 pool_id = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// the request type for the QueryPoolBatchWithdraw RPC method. requestable including specified pool_id and msg_index. +message QueryPoolBatchWithdrawMsgRequest { + // id of the target pool for query + uint64 pool_id = 1; + // target msg_index of the pool + uint64 msg_index = 2; +} + +// the response type for the QueryPoolBatchWithdraw RPC method. This includes a list of all currently existing withdraw messages of the batch and paging results that contain next_key and total count. +message QueryPoolBatchWithdrawMsgsResponse { + repeated WithdrawMsgState withdraws = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. Not supported on this version. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// the response type for the QueryPoolBatchWithdrawMsg RPC method. This includes a batch swap message of the batch. +message QueryPoolBatchWithdrawMsgResponse { + WithdrawMsgState withdraw = 1 [(gogoproto.nullable) = false]; +} diff --git a/proto/tendermint/liquidity/v1beta1/tx.proto b/proto/tendermint/liquidity/v1beta1/tx.proto new file mode 100644 index 00000000000..3f5744c26e9 --- /dev/null +++ b/proto/tendermint/liquidity/v1beta1/tx.proto @@ -0,0 +1,211 @@ +syntax = "proto3"; +package tendermint.liquidity.v1beta1; + +import "gogoproto/gogo.proto"; +import "cosmos_proto/coin.proto"; +import "protoc-gen-openapiv2/options/annotations.proto"; + +option go_package = "github.com/cosmos/gaia/v9/x/liquidity/types"; + +// Msg defines the liquidity Msg service. +service Msg { + + // Submit a create liquidity pool message. + rpc CreatePool(MsgCreatePool) returns (MsgCreatePoolResponse); + + // Submit a deposit to the liquidity pool batch. + rpc DepositWithinBatch(MsgDepositWithinBatch) returns (MsgDepositWithinBatchResponse); + + // Submit a withdraw from the liquidity pool batch. + rpc WithdrawWithinBatch(MsgWithdrawWithinBatch) returns (MsgWithdrawWithinBatchResponse); + + // Submit a swap to the liquidity pool batch. + rpc Swap(MsgSwapWithinBatch) returns (MsgSwapWithinBatchResponse); +} + +// MsgCreatePool defines an sdk.Msg type that supports submitting a create liquidity pool tx. +// +// See: https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md +message MsgCreatePool { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string pool_creator_address = 1 [(gogoproto.moretags) = "yaml:\"pool_creator_address\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "account address of the origin of this message", + example: "\"cosmos1e35y69rhrt7y4yce5l5u73sjnxu0l33wvznyun\"", + format: "sdk.AccAddress" + }]; + + // id of the target pool type, must match the value in the pool. Only pool-type-id 1 is supported. + uint32 pool_type_id = 2 [(gogoproto.moretags) = "yaml:\"pool_type_id\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint32" + }]; + + // reserve coin pair of the pool to deposit. + repeated cosmos.base.v1beta1.Coin deposit_coins = 4 [(gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"deposit_coins\"", + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "[{\"denom\": \"denomX\", \"amount\": \"1000000\"}, {\"denom\": \"denomY\", \"amount\": \"2000000\"}]", + format: "sdk.Coins" + }]; +} + +// MsgCreatePoolResponse defines the Msg/CreatePool response type. +message MsgCreatePoolResponse {} + +// `MsgDepositWithinBatch defines` an `sdk.Msg` type that supports submitting +// a deposit request to the batch of the liquidity pool. +// Deposit is submitted to the batch of the Liquidity pool with the specified +// `pool_id`, `deposit_coins` for reserve. +// This request is stacked in the batch of the liquidity pool, is not processed +// immediately, and is processed in the `endblock` at the same time as other requests. +// +// See: https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md +message MsgDepositWithinBatch { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string depositor_address = 1 [(gogoproto.moretags) = "yaml:\"depositor_address\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "account address of the origin of this message", + example: "\"cosmos1e35y69rhrt7y4yce5l5u73sjnxu0l33wvznyun\"", + format: "sdk.AccAddress" + }]; + + // id of the target pool + uint64 pool_id = 2 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // reserve coin pair of the pool to deposit + repeated cosmos.base.v1beta1.Coin deposit_coins = 3 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"deposit_coins\"", + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "[{\"denom\": \"denomX\", \"amount\": \"1000000\"}, {\"denom\": \"denomY\", \"amount\": \"2000000\"}]", + format: "sdk.Coins" + }]; + +} + +// MsgDepositWithinBatchResponse defines the Msg/DepositWithinBatch response type. +message MsgDepositWithinBatchResponse {} + +// `MsgWithdrawWithinBatch` defines an `sdk.Msg` type that supports submitting +// a withdraw request to the batch of the liquidity pool. +// Withdraw is submitted to the batch from the Liquidity pool with the +// specified `pool_id`, `pool_coin` of the pool. +// This request is stacked in the batch of the liquidity pool, is not processed +// immediately, and is processed in the `endblock` at the same time as other requests. +// +// See: https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md +message MsgWithdrawWithinBatch { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string withdrawer_address = 1 [ (gogoproto.moretags) = "yaml:\"withdrawer_address\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "account address of the origin of this message", + example: "\"cosmos1e35y69rhrt7y4yce5l5u73sjnxu0l33wvznyun\"", + format: "sdk.AccAddress" + }]; + // id of the target pool + uint64 pool_id = 2 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + cosmos.base.v1beta1.Coin pool_coin = 3 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"pool_coin\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4\", \"amount\": \"1000\"}", + format: "sdk.Coin" + }]; +} + +// MsgWithdrawWithinBatchResponse defines the Msg/WithdrawWithinBatch response type. +message MsgWithdrawWithinBatchResponse {} + +// `MsgSwapWithinBatch` defines an sdk.Msg type that supports submitting a swap offer request to the batch of the liquidity pool. +// Submit swap offer to the liquidity pool batch with the specified the `pool_id`, `swap_type_id`, +// `demand_coin_denom` with the coin and the price you're offering +// and `offer_coin_fee` must be half of offer coin amount * current `params.swap_fee_rate` and ceil for reservation to pay fees. +// This request is stacked in the batch of the liquidity pool, is not processed +// immediately, and is processed in the `endblock` at the same time as other requests. +// You must request the same fields as the pool. +// Only the default `swap_type_id` 1 is supported. +// +// See: https://github.com/cosmos/gaia/v9/tree/develop/doc +// https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md +message MsgSwapWithinBatch { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + // address of swap requester + string swap_requester_address = 1 [(gogoproto.moretags) = "yaml:\"swap_requester_address\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "account address of the origin of this message", + example: "\"cosmos1e35y69rhrt7y4yce5l5u73sjnxu0l33wvznyun\"", + format: "sdk.AccAddress" + }]; + // id of swap type, must match the value in the pool. Only `swap_type_id` 1 is supported. + uint64 pool_id = 2 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + }]; + + // id of swap type. Must match the value in the pool. + uint32 swap_type_id = 3 [(gogoproto.moretags) = "yaml:\"swap_type_id\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint32" + }]; + + // offer sdk.coin for the swap request, must match the denom in the pool. + cosmos.base.v1beta1.Coin offer_coin = 4 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"offer_coin\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"denomX\", \"amount\": \"1000000\"}", + format: "sdk.Coin" + }]; + + // denom of demand coin to be exchanged on the swap request, must match the denom in the pool. + string demand_coin_denom = 5 [(gogoproto.moretags) = "yaml:\"demand_coin_denom\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"denomB\"", + }]; + + // half of offer coin amount * params.swap_fee_rate and ceil for reservation to pay fees. + cosmos.base.v1beta1.Coin offer_coin_fee = 6 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"offer_coin_fee\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"denomX\", \"amount\": \"5000\"}", + format: "sdk.Coin" + } + ]; + + // limit order price for the order, the price is the exchange ratio of X/Y + // where X is the amount of the first coin and Y is the amount + // of the second coin when their denoms are sorted alphabetically. + string order_price = 7 [ + (gogoproto.moretags) = "yaml:\"order_price\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1.1\"", + format: "sdk.Dec" + }]; +} + +// MsgSwapWithinBatchResponse defines the Msg/Swap response type. +message MsgSwapWithinBatchResponse {} diff --git a/third_party/proto/confio/proofs.proto b/third_party/proto/confio/proofs.proto new file mode 100644 index 00000000000..da43503ecbd --- /dev/null +++ b/third_party/proto/confio/proofs.proto @@ -0,0 +1,234 @@ +syntax = "proto3"; + +package ics23; +option go_package = "github.com/confio/ics23/go"; + +enum HashOp { + // NO_HASH is the default if no data passed. Note this is an illegal argument some places. + NO_HASH = 0; + SHA256 = 1; + SHA512 = 2; + KECCAK = 3; + RIPEMD160 = 4; + BITCOIN = 5; // ripemd160(sha256(x)) +} + +/** +LengthOp defines how to process the key and value of the LeafOp +to include length information. After encoding the length with the given +algorithm, the length will be prepended to the key and value bytes. +(Each one with it's own encoded length) +*/ +enum LengthOp { + // NO_PREFIX don't include any length info + NO_PREFIX = 0; + // VAR_PROTO uses protobuf (and go-amino) varint encoding of the length + VAR_PROTO = 1; + // VAR_RLP uses rlp int encoding of the length + VAR_RLP = 2; + // FIXED32_BIG uses big-endian encoding of the length as a 32 bit integer + FIXED32_BIG = 3; + // FIXED32_LITTLE uses little-endian encoding of the length as a 32 bit integer + FIXED32_LITTLE = 4; + // FIXED64_BIG uses big-endian encoding of the length as a 64 bit integer + FIXED64_BIG = 5; + // FIXED64_LITTLE uses little-endian encoding of the length as a 64 bit integer + FIXED64_LITTLE = 6; + // REQUIRE_32_BYTES is like NONE, but will fail if the input is not exactly 32 bytes (sha256 output) + REQUIRE_32_BYTES = 7; + // REQUIRE_64_BYTES is like NONE, but will fail if the input is not exactly 64 bytes (sha512 output) + REQUIRE_64_BYTES = 8; +} + +/** +ExistenceProof takes a key and a value and a set of steps to perform on it. +The result of peforming all these steps will provide a "root hash", which can +be compared to the value in a header. + +Since it is computationally infeasible to produce a hash collission for any of the used +cryptographic hash functions, if someone can provide a series of operations to transform +a given key and value into a root hash that matches some trusted root, these key and values +must be in the referenced merkle tree. + +The only possible issue is maliablity in LeafOp, such as providing extra prefix data, +which should be controlled by a spec. Eg. with lengthOp as NONE, + prefix = FOO, key = BAR, value = CHOICE +and + prefix = F, key = OOBAR, value = CHOICE +would produce the same value. + +With LengthOp this is tricker but not impossible. Which is why the "leafPrefixEqual" field +in the ProofSpec is valuable to prevent this mutability. And why all trees should +length-prefix the data before hashing it. +*/ +message ExistenceProof { + bytes key = 1; + bytes value = 2; + LeafOp leaf = 3; + repeated InnerOp path = 4; +} + +/* +NonExistenceProof takes a proof of two neighbors, one left of the desired key, +one right of the desired key. If both proofs are valid AND they are neighbors, +then there is no valid proof for the given key. +*/ +message NonExistenceProof { + bytes key = 1; // TODO: remove this as unnecessary??? we prove a range + ExistenceProof left = 2; + ExistenceProof right = 3; +} + +/* +CommitmentProof is either an ExistenceProof or a NonExistenceProof, or a Batch of such messages +*/ +message CommitmentProof { + oneof proof { + ExistenceProof exist = 1; + NonExistenceProof nonexist = 2; + BatchProof batch = 3; + CompressedBatchProof compressed = 4; + } +} + +/** +LeafOp represents the raw key-value data we wish to prove, and +must be flexible to represent the internal transformation from +the original key-value pairs into the basis hash, for many existing +merkle trees. + +key and value are passed in. So that the signature of this operation is: + leafOp(key, value) -> output + +To process this, first prehash the keys and values if needed (ANY means no hash in this case): + hkey = prehashKey(key) + hvalue = prehashValue(value) + +Then combine the bytes, and hash it + output = hash(prefix || length(hkey) || hkey || length(hvalue) || hvalue) +*/ +message LeafOp { + HashOp hash = 1; + HashOp prehash_key = 2; + HashOp prehash_value = 3; + LengthOp length = 4; + // prefix is a fixed bytes that may optionally be included at the beginning to differentiate + // a leaf node from an inner node. + bytes prefix = 5; +} + +/** +InnerOp represents a merkle-proof step that is not a leaf. +It represents concatenating two children and hashing them to provide the next result. + +The result of the previous step is passed in, so the signature of this op is: + innerOp(child) -> output + +The result of applying InnerOp should be: + output = op.hash(op.prefix || child || op.suffix) + + where the || operator is concatenation of binary data, +and child is the result of hashing all the tree below this step. + +Any special data, like prepending child with the length, or prepending the entire operation with +some value to differentiate from leaf nodes, should be included in prefix and suffix. +If either of prefix or suffix is empty, we just treat it as an empty string +*/ +message InnerOp { + HashOp hash = 1; + bytes prefix = 2; + bytes suffix = 3; +} + + +/** +ProofSpec defines what the expected parameters are for a given proof type. +This can be stored in the client and used to validate any incoming proofs. + + verify(ProofSpec, Proof) -> Proof | Error + +As demonstrated in tests, if we don't fix the algorithm used to calculate the +LeafHash for a given tree, there are many possible key-value pairs that can +generate a given hash (by interpretting the preimage differently). +We need this for proper security, requires client knows a priori what +tree format server uses. But not in code, rather a configuration object. +*/ +message ProofSpec { + // any field in the ExistenceProof must be the same as in this spec. + // except Prefix, which is just the first bytes of prefix (spec can be longer) + LeafOp leaf_spec = 1; + InnerSpec inner_spec = 2; + // max_depth (if > 0) is the maximum number of InnerOps allowed (mainly for fixed-depth tries) + int32 max_depth = 3; + // min_depth (if > 0) is the minimum number of InnerOps allowed (mainly for fixed-depth tries) + int32 min_depth = 4; +} + +/* +InnerSpec contains all store-specific structure info to determine if two proofs from a +given store are neighbors. + +This enables: + + isLeftMost(spec: InnerSpec, op: InnerOp) + isRightMost(spec: InnerSpec, op: InnerOp) + isLeftNeighbor(spec: InnerSpec, left: InnerOp, right: InnerOp) +*/ +message InnerSpec { + // Child order is the ordering of the children node, must count from 0 + // iavl tree is [0, 1] (left then right) + // merk is [0, 2, 1] (left, right, here) + repeated int32 child_order = 1; + int32 child_size = 2; + int32 min_prefix_length = 3; + int32 max_prefix_length = 4; + // empty child is the prehash image that is used when one child is nil (eg. 20 bytes of 0) + bytes empty_child = 5; + // hash is the algorithm that must be used for each InnerOp + HashOp hash = 6; +} + +/* +BatchProof is a group of multiple proof types than can be compressed +*/ +message BatchProof { + repeated BatchEntry entries = 1; +} + +// Use BatchEntry not CommitmentProof, to avoid recursion +message BatchEntry { + oneof proof { + ExistenceProof exist = 1; + NonExistenceProof nonexist = 2; + } +} + + +/****** all items here are compressed forms *******/ + +message CompressedBatchProof { + repeated CompressedBatchEntry entries = 1; + repeated InnerOp lookup_inners = 2; +} + +// Use BatchEntry not CommitmentProof, to avoid recursion +message CompressedBatchEntry { + oneof proof { + CompressedExistenceProof exist = 1; + CompressedNonExistenceProof nonexist = 2; + } +} + +message CompressedExistenceProof { + bytes key = 1; + bytes value = 2; + LeafOp leaf = 3; + // these are indexes into the lookup_inners table in CompressedBatchProof + repeated int32 path = 4; +} + +message CompressedNonExistenceProof { + bytes key = 1; // TODO: remove this as unnecessary??? we prove a range + CompressedExistenceProof left = 2; + CompressedExistenceProof right = 3; +} diff --git a/third_party/proto/cosmos_proto/coin.proto b/third_party/proto/cosmos_proto/coin.proto new file mode 100644 index 00000000000..fab75284b7f --- /dev/null +++ b/third_party/proto/cosmos_proto/coin.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; +package cosmos.base.v1beta1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/types"; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.stringer_all) = false; + +// 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. +message Coin { + option (gogoproto.equal) = true; + + string denom = 1; + string amount = 2 [(gogoproto.customtype) = "Int", (gogoproto.nullable) = false]; +} + +// 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. +message DecCoin { + option (gogoproto.equal) = true; + + string denom = 1; + string amount = 2 [(gogoproto.customtype) = "Dec", (gogoproto.nullable) = false]; +} + +// IntProto defines a Protobuf wrapper around an Int object. +message IntProto { + string int = 1 [(gogoproto.customtype) = "Int", (gogoproto.nullable) = false]; +} + +// DecProto defines a Protobuf wrapper around a Dec object. +message DecProto { + string dec = 1 [(gogoproto.customtype) = "Dec", (gogoproto.nullable) = false]; +} diff --git a/third_party/proto/cosmos_proto/pagination.proto b/third_party/proto/cosmos_proto/pagination.proto new file mode 100644 index 00000000000..2a8cbccedd8 --- /dev/null +++ b/third_party/proto/cosmos_proto/pagination.proto @@ -0,0 +1,50 @@ +syntax = "proto3"; +package cosmos.base.query.v1beta1; + +option go_package = "github.com/cosmos/cosmos-sdk/types/query"; + +// PageRequest is to be embedded in gRPC request messages for efficient +// pagination. Ex: +// +// message SomeRequest { +// Foo some_parameter = 1; +// PageRequest pagination = 2; +// } +message PageRequest { + // 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. + bytes key = 1; + + // 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. + uint64 offset = 2; + + // 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. + uint64 limit = 3; + + // 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. + bool count_total = 4; +} + +// 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; +// } +message PageResponse { + // next_key is the key to be passed to PageRequest.key to + // query the next page most efficiently + bytes next_key = 1; + + // total is total number of results available if PageRequest.count_total + // was set, its value is undefined otherwise + uint64 total = 2; +} diff --git a/third_party/proto/google/protobuf/any.proto b/third_party/proto/google/protobuf/any.proto index 58b511583a8..1431810ea45 100644 --- a/third_party/proto/google/protobuf/any.proto +++ b/third_party/proto/google/protobuf/any.proto @@ -156,9 +156,6 @@ message Any { bytes value = 2; option (gogoproto.typedecl) = false; - option (gogoproto.goproto_stringer) = false; - option (gogoproto.gostring) = false; - option (gogoproto.stringer) = false; } option (gogoproto.goproto_registration) = false; diff --git a/third_party/proto/protoc-gen-openapiv2/options/BUILD.bazel b/third_party/proto/protoc-gen-openapiv2/options/BUILD.bazel new file mode 100644 index 00000000000..36369994172 --- /dev/null +++ b/third_party/proto/protoc-gen-openapiv2/options/BUILD.bazel @@ -0,0 +1,38 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "options_proto_files", + srcs = [ + "annotations.proto", + "openapiv2.proto", + ], +) + +go_library( + name = "go_default_library", + embed = [":options_go_proto"], + importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options", +) + +proto_library( + name = "options_proto", + srcs = [ + "annotations.proto", + "openapiv2.proto", + ], + deps = [ + "@com_google_protobuf//:descriptor_proto", + "@com_google_protobuf//:struct_proto", + ], +) + +go_proto_library( + name = "options_go_proto", + compilers = ["//:go_apiv2"], + importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options", + proto = ":options_proto", +) diff --git a/third_party/proto/protoc-gen-openapiv2/options/annotations.pb.go b/third_party/proto/protoc-gen-openapiv2/options/annotations.pb.go new file mode 100644 index 00000000000..dbe5351688b --- /dev/null +++ b/third_party/proto/protoc-gen-openapiv2/options/annotations.pb.go @@ -0,0 +1,241 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0 +// protoc v3.12.0 +// source: protoc-gen-openapiv2/options/annotations.proto + +package options + +import ( + proto "github.com/golang/protobuf/proto" + descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +var file_protoc_gen_openapiv2_options_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptor.FileOptions)(nil), + ExtensionType: (*Swagger)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger", + Tag: "bytes,1042,opt,name=openapiv2_swagger", + Filename: "protoc-gen-openapiv2/options/annotations.proto", + }, + { + ExtendedType: (*descriptor.MethodOptions)(nil), + ExtensionType: (*Operation)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation", + Tag: "bytes,1042,opt,name=openapiv2_operation", + Filename: "protoc-gen-openapiv2/options/annotations.proto", + }, + { + ExtendedType: (*descriptor.MessageOptions)(nil), + ExtensionType: (*Schema)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema", + Tag: "bytes,1042,opt,name=openapiv2_schema", + Filename: "protoc-gen-openapiv2/options/annotations.proto", + }, + { + ExtendedType: (*descriptor.ServiceOptions)(nil), + ExtensionType: (*Tag)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag", + Tag: "bytes,1042,opt,name=openapiv2_tag", + Filename: "protoc-gen-openapiv2/options/annotations.proto", + }, + { + ExtendedType: (*descriptor.FieldOptions)(nil), + ExtensionType: (*JSONSchema)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field", + Tag: "bytes,1042,opt,name=openapiv2_field", + Filename: "protoc-gen-openapiv2/options/annotations.proto", + }, +} + +// Extension fields to descriptor.FileOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.Swagger openapiv2_swagger = 1042; + E_Openapiv2Swagger = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[0] +) + +// Extension fields to descriptor.MethodOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.Operation openapiv2_operation = 1042; + E_Openapiv2Operation = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[1] +) + +// Extension fields to descriptor.MessageOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.Schema openapiv2_schema = 1042; + E_Openapiv2Schema = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[2] +) + +// Extension fields to descriptor.ServiceOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.Tag openapiv2_tag = 1042; + E_Openapiv2Tag = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[3] +) + +// Extension fields to descriptor.FieldOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.JSONSchema openapiv2_field = 1042; + E_Openapiv2Field = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[4] +) + +var File_protoc_gen_openapiv2_options_annotations_proto protoreflect.FileDescriptor + +var file_protoc_gen_openapiv2_options_annotations_proto_rawDesc = []byte{ + 0x0a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, + 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, + 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x29, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x20, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2c, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x7e, 0x0a, 0x11, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, + 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x92, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x52, 0x10, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x3a, 0x86, 0x01, 0x0a, 0x13, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x12, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x7e, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x3a, 0x75, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x5f, 0x74, 0x61, 0x67, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x0c, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x54, 0x61, 0x67, 0x3a, 0x7e, 0x0a, 0x0f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1d, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0e, 0x6f, 0x70, 0x65, + 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x65, + 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, + 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var file_protoc_gen_openapiv2_options_annotations_proto_goTypes = []interface{}{ + (*descriptor.FileOptions)(nil), // 0: google.protobuf.FileOptions + (*descriptor.MethodOptions)(nil), // 1: google.protobuf.MethodOptions + (*descriptor.MessageOptions)(nil), // 2: google.protobuf.MessageOptions + (*descriptor.ServiceOptions)(nil), // 3: google.protobuf.ServiceOptions + (*descriptor.FieldOptions)(nil), // 4: google.protobuf.FieldOptions + (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger + (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation + (*Schema)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Schema + (*Tag)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Tag + (*JSONSchema)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema +} +var file_protoc_gen_openapiv2_options_annotations_proto_depIdxs = []int32{ + 0, // 0: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger:extendee -> google.protobuf.FileOptions + 1, // 1: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation:extendee -> google.protobuf.MethodOptions + 2, // 2: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema:extendee -> google.protobuf.MessageOptions + 3, // 3: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag:extendee -> google.protobuf.ServiceOptions + 4, // 4: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field:extendee -> google.protobuf.FieldOptions + 5, // 5: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger + 6, // 6: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation + 7, // 7: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema + 8, // 8: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Tag + 9, // 9: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 5, // [5:10] is the sub-list for extension type_name + 0, // [0:5] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_protoc_gen_openapiv2_options_annotations_proto_init() } +func file_protoc_gen_openapiv2_options_annotations_proto_init() { + if File_protoc_gen_openapiv2_options_annotations_proto != nil { + return + } + file_protoc_gen_openapiv2_options_openapiv2_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_protoc_gen_openapiv2_options_annotations_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 5, + NumServices: 0, + }, + GoTypes: file_protoc_gen_openapiv2_options_annotations_proto_goTypes, + DependencyIndexes: file_protoc_gen_openapiv2_options_annotations_proto_depIdxs, + ExtensionInfos: file_protoc_gen_openapiv2_options_annotations_proto_extTypes, + }.Build() + File_protoc_gen_openapiv2_options_annotations_proto = out.File + file_protoc_gen_openapiv2_options_annotations_proto_rawDesc = nil + file_protoc_gen_openapiv2_options_annotations_proto_goTypes = nil + file_protoc_gen_openapiv2_options_annotations_proto_depIdxs = nil +} diff --git a/third_party/proto/protoc-gen-openapiv2/options/annotations.proto b/third_party/proto/protoc-gen-openapiv2/options/annotations.proto new file mode 100644 index 00000000000..1c189e2065c --- /dev/null +++ b/third_party/proto/protoc-gen-openapiv2/options/annotations.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; + +package grpc.gateway.protoc_gen_openapiv2.options; + +option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"; + +import "google/protobuf/descriptor.proto"; +import "protoc-gen-openapiv2/options/openapiv2.proto"; + +extend google.protobuf.FileOptions { + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + Swagger openapiv2_swagger = 1042; +} +extend google.protobuf.MethodOptions { + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + Operation openapiv2_operation = 1042; +} +extend google.protobuf.MessageOptions { + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + Schema openapiv2_schema = 1042; +} +extend google.protobuf.ServiceOptions { + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + Tag openapiv2_tag = 1042; +} +extend google.protobuf.FieldOptions { + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + JSONSchema openapiv2_field = 1042; +} diff --git a/third_party/proto/protoc-gen-openapiv2/options/openapiv2.pb.go b/third_party/proto/protoc-gen-openapiv2/options/openapiv2.pb.go new file mode 100644 index 00000000000..e3ef175d0b0 --- /dev/null +++ b/third_party/proto/protoc-gen-openapiv2/options/openapiv2.pb.go @@ -0,0 +1,2790 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0 +// protoc v3.12.0 +// source: protoc-gen-openapiv2/options/openapiv2.proto + +package options + +import ( + proto "github.com/golang/protobuf/proto" + _struct "github.com/golang/protobuf/ptypes/struct" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// Scheme describes the schemes supported by the OpenAPI Swagger +// and Operation objects. +type Scheme int32 + +const ( + Scheme_UNKNOWN Scheme = 0 + Scheme_HTTP Scheme = 1 + Scheme_HTTPS Scheme = 2 + Scheme_WS Scheme = 3 + Scheme_WSS Scheme = 4 +) + +// Enum value maps for Scheme. +var ( + Scheme_name = map[int32]string{ + 0: "UNKNOWN", + 1: "HTTP", + 2: "HTTPS", + 3: "WS", + 4: "WSS", + } + Scheme_value = map[string]int32{ + "UNKNOWN": 0, + "HTTP": 1, + "HTTPS": 2, + "WS": 3, + "WSS": 4, + } +) + +func (x Scheme) Enum() *Scheme { + p := new(Scheme) + *p = x + return p +} + +func (x Scheme) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Scheme) Descriptor() protoreflect.EnumDescriptor { + return file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[0].Descriptor() +} + +func (Scheme) Type() protoreflect.EnumType { + return &file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[0] +} + +func (x Scheme) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Scheme.Descriptor instead. +func (Scheme) EnumDescriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{0} +} + +type JSONSchema_JSONSchemaSimpleTypes int32 + +const ( + JSONSchema_UNKNOWN JSONSchema_JSONSchemaSimpleTypes = 0 + JSONSchema_ARRAY JSONSchema_JSONSchemaSimpleTypes = 1 + JSONSchema_BOOLEAN JSONSchema_JSONSchemaSimpleTypes = 2 + JSONSchema_INTEGER JSONSchema_JSONSchemaSimpleTypes = 3 + JSONSchema_NULL JSONSchema_JSONSchemaSimpleTypes = 4 + JSONSchema_NUMBER JSONSchema_JSONSchemaSimpleTypes = 5 + JSONSchema_OBJECT JSONSchema_JSONSchemaSimpleTypes = 6 + JSONSchema_STRING JSONSchema_JSONSchemaSimpleTypes = 7 +) + +// Enum value maps for JSONSchema_JSONSchemaSimpleTypes. +var ( + JSONSchema_JSONSchemaSimpleTypes_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ARRAY", + 2: "BOOLEAN", + 3: "INTEGER", + 4: "NULL", + 5: "NUMBER", + 6: "OBJECT", + 7: "STRING", + } + JSONSchema_JSONSchemaSimpleTypes_value = map[string]int32{ + "UNKNOWN": 0, + "ARRAY": 1, + "BOOLEAN": 2, + "INTEGER": 3, + "NULL": 4, + "NUMBER": 5, + "OBJECT": 6, + "STRING": 7, + } +) + +func (x JSONSchema_JSONSchemaSimpleTypes) Enum() *JSONSchema_JSONSchemaSimpleTypes { + p := new(JSONSchema_JSONSchemaSimpleTypes) + *p = x + return p +} + +func (x JSONSchema_JSONSchemaSimpleTypes) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (JSONSchema_JSONSchemaSimpleTypes) Descriptor() protoreflect.EnumDescriptor { + return file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[1].Descriptor() +} + +func (JSONSchema_JSONSchemaSimpleTypes) Type() protoreflect.EnumType { + return &file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[1] +} + +func (x JSONSchema_JSONSchemaSimpleTypes) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use JSONSchema_JSONSchemaSimpleTypes.Descriptor instead. +func (JSONSchema_JSONSchemaSimpleTypes) EnumDescriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{9, 0} +} + +// The type of the security scheme. Valid values are "basic", +// "apiKey" or "oauth2". +type SecurityScheme_Type int32 + +const ( + SecurityScheme_TYPE_INVALID SecurityScheme_Type = 0 + SecurityScheme_TYPE_BASIC SecurityScheme_Type = 1 + SecurityScheme_TYPE_API_KEY SecurityScheme_Type = 2 + SecurityScheme_TYPE_OAUTH2 SecurityScheme_Type = 3 +) + +// Enum value maps for SecurityScheme_Type. +var ( + SecurityScheme_Type_name = map[int32]string{ + 0: "TYPE_INVALID", + 1: "TYPE_BASIC", + 2: "TYPE_API_KEY", + 3: "TYPE_OAUTH2", + } + SecurityScheme_Type_value = map[string]int32{ + "TYPE_INVALID": 0, + "TYPE_BASIC": 1, + "TYPE_API_KEY": 2, + "TYPE_OAUTH2": 3, + } +) + +func (x SecurityScheme_Type) Enum() *SecurityScheme_Type { + p := new(SecurityScheme_Type) + *p = x + return p +} + +func (x SecurityScheme_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SecurityScheme_Type) Descriptor() protoreflect.EnumDescriptor { + return file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[2].Descriptor() +} + +func (SecurityScheme_Type) Type() protoreflect.EnumType { + return &file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[2] +} + +func (x SecurityScheme_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SecurityScheme_Type.Descriptor instead. +func (SecurityScheme_Type) EnumDescriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 0} +} + +// The location of the API key. Valid values are "query" or "header". +type SecurityScheme_In int32 + +const ( + SecurityScheme_IN_INVALID SecurityScheme_In = 0 + SecurityScheme_IN_QUERY SecurityScheme_In = 1 + SecurityScheme_IN_HEADER SecurityScheme_In = 2 +) + +// Enum value maps for SecurityScheme_In. +var ( + SecurityScheme_In_name = map[int32]string{ + 0: "IN_INVALID", + 1: "IN_QUERY", + 2: "IN_HEADER", + } + SecurityScheme_In_value = map[string]int32{ + "IN_INVALID": 0, + "IN_QUERY": 1, + "IN_HEADER": 2, + } +) + +func (x SecurityScheme_In) Enum() *SecurityScheme_In { + p := new(SecurityScheme_In) + *p = x + return p +} + +func (x SecurityScheme_In) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SecurityScheme_In) Descriptor() protoreflect.EnumDescriptor { + return file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[3].Descriptor() +} + +func (SecurityScheme_In) Type() protoreflect.EnumType { + return &file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[3] +} + +func (x SecurityScheme_In) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SecurityScheme_In.Descriptor instead. +func (SecurityScheme_In) EnumDescriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 1} +} + +// The flow used by the OAuth2 security scheme. Valid values are +// "implicit", "password", "application" or "accessCode". +type SecurityScheme_Flow int32 + +const ( + SecurityScheme_FLOW_INVALID SecurityScheme_Flow = 0 + SecurityScheme_FLOW_IMPLICIT SecurityScheme_Flow = 1 + SecurityScheme_FLOW_PASSWORD SecurityScheme_Flow = 2 + SecurityScheme_FLOW_APPLICATION SecurityScheme_Flow = 3 + SecurityScheme_FLOW_ACCESS_CODE SecurityScheme_Flow = 4 +) + +// Enum value maps for SecurityScheme_Flow. +var ( + SecurityScheme_Flow_name = map[int32]string{ + 0: "FLOW_INVALID", + 1: "FLOW_IMPLICIT", + 2: "FLOW_PASSWORD", + 3: "FLOW_APPLICATION", + 4: "FLOW_ACCESS_CODE", + } + SecurityScheme_Flow_value = map[string]int32{ + "FLOW_INVALID": 0, + "FLOW_IMPLICIT": 1, + "FLOW_PASSWORD": 2, + "FLOW_APPLICATION": 3, + "FLOW_ACCESS_CODE": 4, + } +) + +func (x SecurityScheme_Flow) Enum() *SecurityScheme_Flow { + p := new(SecurityScheme_Flow) + *p = x + return p +} + +func (x SecurityScheme_Flow) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SecurityScheme_Flow) Descriptor() protoreflect.EnumDescriptor { + return file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[4].Descriptor() +} + +func (SecurityScheme_Flow) Type() protoreflect.EnumType { + return &file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[4] +} + +func (x SecurityScheme_Flow) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SecurityScheme_Flow.Descriptor instead. +func (SecurityScheme_Flow) EnumDescriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 2} +} + +// `Swagger` is a representation of OpenAPI v2 specification's Swagger object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// title: "Echo API"; +// version: "1.0"; +// description: "; +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// }; +// schemes: HTTPS; +// consumes: "application/json"; +// produces: "application/json"; +// }; +// +type Swagger struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Specifies the OpenAPI Specification version being used. It can be + // used by the OpenAPI UI and other clients to interpret the API listing. The + // value MUST be "2.0". + Swagger string `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"` + // Provides metadata about the API. The metadata can be used by the + // clients if needed. + Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` + // The host (name or ip) serving the API. This MUST be the host only and does + // not include the scheme nor sub-paths. It MAY include a port. If the host is + // not included, the host serving the documentation is to be used (including + // the port). The host does not support path templating. + Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` + // The base path on which the API is served, which is relative to the host. If + // it is not included, the API is served directly under the host. The value + // MUST start with a leading slash (/). The basePath does not support path + // templating. + // Note that using `base_path` does not change the endpoint paths that are + // generated in the resulting OpenAPI file. If you wish to use `base_path` + // with relatively generated OpenAPI paths, the `base_path` prefix must be + // manually removed from your `google.api.http` paths and your code changed to + // serve the API from the `base_path`. + BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"` + // The transfer protocol of the API. Values MUST be from the list: "http", + // "https", "ws", "wss". If the schemes is not included, the default scheme to + // be used is the one used to access the OpenAPI definition itself. + Schemes []Scheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` + // A list of MIME types the APIs can consume. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + // A list of MIME types the APIs can produce. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + // An object to hold responses that can be used across operations. This + // property does not define global responses for all operations. + Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Security scheme definitions that can be used across the specification. + SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"` + // A declaration of which security schemes are applied for the API as a whole. + // The list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). + // Individual operations can override this definition. + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + // Additional external documentation. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + Extensions map[string]*_struct.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Swagger) Reset() { + *x = Swagger{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Swagger) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Swagger) ProtoMessage() {} + +func (x *Swagger) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Swagger.ProtoReflect.Descriptor instead. +func (*Swagger) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{0} +} + +func (x *Swagger) GetSwagger() string { + if x != nil { + return x.Swagger + } + return "" +} + +func (x *Swagger) GetInfo() *Info { + if x != nil { + return x.Info + } + return nil +} + +func (x *Swagger) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + +func (x *Swagger) GetBasePath() string { + if x != nil { + return x.BasePath + } + return "" +} + +func (x *Swagger) GetSchemes() []Scheme { + if x != nil { + return x.Schemes + } + return nil +} + +func (x *Swagger) GetConsumes() []string { + if x != nil { + return x.Consumes + } + return nil +} + +func (x *Swagger) GetProduces() []string { + if x != nil { + return x.Produces + } + return nil +} + +func (x *Swagger) GetResponses() map[string]*Response { + if x != nil { + return x.Responses + } + return nil +} + +func (x *Swagger) GetSecurityDefinitions() *SecurityDefinitions { + if x != nil { + return x.SecurityDefinitions + } + return nil +} + +func (x *Swagger) GetSecurity() []*SecurityRequirement { + if x != nil { + return x.Security + } + return nil +} + +func (x *Swagger) GetExternalDocs() *ExternalDocumentation { + if x != nil { + return x.ExternalDocs + } + return nil +} + +func (x *Swagger) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `Operation` is a representation of OpenAPI v2 specification's Operation object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject +// +// Example: +// +// service EchoService { +// rpc Echo(SimpleMessage) returns (SimpleMessage) { +// option (google.api.http) = { +// get: "/v1/example/echo/{id}" +// }; +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { +// summary: "Get a message."; +// operation_id: "getMessage"; +// tags: "echo"; +// responses: { +// key: "200" +// value: { +// description: "OK"; +// } +// } +// }; +// } +// } +type Operation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A list of tags for API documentation control. Tags can be used for logical + // grouping of operations by resources or any other qualifier. + Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` + // A short summary of what the operation does. For maximum readability in the + // swagger-ui, this field SHOULD be less than 120 characters. + Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + // A verbose explanation of the operation behavior. GFM syntax can be used for + // rich text representation. + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // Additional external documentation for this operation. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + // Unique string used to identify the operation. The id MUST be unique among + // all operations described in the API. Tools and libraries MAY use the + // operationId to uniquely identify an operation, therefore, it is recommended + // to follow common programming naming conventions. + OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` + // A list of MIME types the operation can consume. This overrides the consumes + // definition at the OpenAPI Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + // A list of MIME types the operation can produce. This overrides the produces + // definition at the OpenAPI Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + // The list of possible responses as they are returned from executing this + // operation. + Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // The transfer protocol for the operation. Values MUST be from the list: + // "http", "https", "ws", "wss". The value overrides the OpenAPI Object + // schemes definition. + Schemes []Scheme `protobuf:"varint,10,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` + // Declares this operation to be deprecated. Usage of the declared operation + // should be refrained. Default value is false. + Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + // A declaration of which security schemes are applied for this operation. The + // list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). This + // definition overrides any declared top-level security. To remove a top-level + // security declaration, an empty array can be used. + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + Extensions map[string]*_struct.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Operation) Reset() { + *x = Operation{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Operation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Operation) ProtoMessage() {} + +func (x *Operation) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Operation.ProtoReflect.Descriptor instead. +func (*Operation) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{1} +} + +func (x *Operation) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *Operation) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +func (x *Operation) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Operation) GetExternalDocs() *ExternalDocumentation { + if x != nil { + return x.ExternalDocs + } + return nil +} + +func (x *Operation) GetOperationId() string { + if x != nil { + return x.OperationId + } + return "" +} + +func (x *Operation) GetConsumes() []string { + if x != nil { + return x.Consumes + } + return nil +} + +func (x *Operation) GetProduces() []string { + if x != nil { + return x.Produces + } + return nil +} + +func (x *Operation) GetResponses() map[string]*Response { + if x != nil { + return x.Responses + } + return nil +} + +func (x *Operation) GetSchemes() []Scheme { + if x != nil { + return x.Schemes + } + return nil +} + +func (x *Operation) GetDeprecated() bool { + if x != nil { + return x.Deprecated + } + return false +} + +func (x *Operation) GetSecurity() []*SecurityRequirement { + if x != nil { + return x.Security + } + return nil +} + +func (x *Operation) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `Header` is a representation of OpenAPI v2 specification's Header object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject +// +type Header struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // `Description` is a short description of the header. + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported. + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + // `Format` The extending format for the previously mentioned type. + Format string `protobuf:"bytes,3,opt,name=format,proto3" json:"format,omitempty"` + // `Default` Declares the value of the header that the server will use if none is provided. + // See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. + // Unlike JSON Schema this value MUST conform to the defined type for the header. + Default string `protobuf:"bytes,6,opt,name=default,proto3" json:"default,omitempty"` + // 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3. + Pattern string `protobuf:"bytes,13,opt,name=pattern,proto3" json:"pattern,omitempty"` +} + +func (x *Header) Reset() { + *x = Header{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Header) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Header) ProtoMessage() {} + +func (x *Header) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Header.ProtoReflect.Descriptor instead. +func (*Header) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{2} +} + +func (x *Header) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Header) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Header) GetFormat() string { + if x != nil { + return x.Format + } + return "" +} + +func (x *Header) GetDefault() string { + if x != nil { + return x.Default + } + return "" +} + +func (x *Header) GetPattern() string { + if x != nil { + return x.Pattern + } + return "" +} + +// `Response` is a representation of OpenAPI v2 specification's Response object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject +// +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // `Description` is a short description of the response. + // GFM syntax can be used for rich text representation. + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // `Schema` optionally defines the structure of the response. + // If `Schema` is not provided, it means there is no content to the response. + Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` + // `Headers` A list of headers that are sent with the response. + // `Header` name is expected to be a string in the canonical format of the MIME header key + // See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey + Headers map[string]*Header `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // `Examples` gives per-mimetype response examples. + // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object + Examples map[string]string `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Extensions map[string]*_struct.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Response) Reset() { + *x = Response{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{3} +} + +func (x *Response) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Response) GetSchema() *Schema { + if x != nil { + return x.Schema + } + return nil +} + +func (x *Response) GetHeaders() map[string]*Header { + if x != nil { + return x.Headers + } + return nil +} + +func (x *Response) GetExamples() map[string]string { + if x != nil { + return x.Examples + } + return nil +} + +func (x *Response) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `Info` is a representation of OpenAPI v2 specification's Info object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// title: "Echo API"; +// version: "1.0"; +// description: "; +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// }; +// ... +// }; +// +type Info struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The title of the application. + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // A short description of the application. GFM syntax can be used for rich + // text representation. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // The Terms of Service for the API. + TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"` + // The contact information for the exposed API. + Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"` + // The license information for the exposed API. + License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"` + // Provides the version of the application API (not to be confused + // with the specification version). + Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` + Extensions map[string]*_struct.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Info) Reset() { + *x = Info{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Info) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Info) ProtoMessage() {} + +func (x *Info) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Info.ProtoReflect.Descriptor instead. +func (*Info) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{4} +} + +func (x *Info) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *Info) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Info) GetTermsOfService() string { + if x != nil { + return x.TermsOfService + } + return "" +} + +func (x *Info) GetContact() *Contact { + if x != nil { + return x.Contact + } + return nil +} + +func (x *Info) GetLicense() *License { + if x != nil { + return x.License + } + return nil +} + +func (x *Info) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *Info) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `Contact` is a representation of OpenAPI v2 specification's Contact object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// ... +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// ... +// }; +// ... +// }; +// +type Contact struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The identifying name of the contact person/organization. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The URL pointing to the contact information. MUST be in the format of a + // URL. + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + // The email address of the contact person/organization. MUST be in the format + // of an email address. + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` +} + +func (x *Contact) Reset() { + *x = Contact{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Contact) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Contact) ProtoMessage() {} + +func (x *Contact) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Contact.ProtoReflect.Descriptor instead. +func (*Contact) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{5} +} + +func (x *Contact) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Contact) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Contact) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +// `License` is a representation of OpenAPI v2 specification's License object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// ... +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// ... +// }; +// ... +// }; +// +type License struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The license name used for the API. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // A URL to the license used for the API. MUST be in the format of a URL. + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *License) Reset() { + *x = License{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *License) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*License) ProtoMessage() {} + +func (x *License) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use License.ProtoReflect.Descriptor instead. +func (*License) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{6} +} + +func (x *License) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *License) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +// `ExternalDocumentation` is a representation of OpenAPI v2 specification's +// ExternalDocumentation object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// ... +// external_docs: { +// description: "More about gRPC-Gateway"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// } +// ... +// }; +// +type ExternalDocumentation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A short description of the target documentation. GFM syntax can be used for + // rich text representation. + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // The URL for the target documentation. Value MUST be in the format + // of a URL. + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *ExternalDocumentation) Reset() { + *x = ExternalDocumentation{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExternalDocumentation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExternalDocumentation) ProtoMessage() {} + +func (x *ExternalDocumentation) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExternalDocumentation.ProtoReflect.Descriptor instead. +func (*ExternalDocumentation) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{7} +} + +func (x *ExternalDocumentation) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *ExternalDocumentation) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +// `Schema` is a representation of OpenAPI v2 specification's Schema object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject +// +type Schema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JsonSchema *JSONSchema `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"` + // Adds support for polymorphism. The discriminator is the schema property + // name that is used to differentiate between other schema that inherit this + // schema. The property name used MUST be defined at this schema and it MUST + // be in the required property list. When used, the value MUST be the name of + // this schema or any schema that inherits it. + Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"` + // Relevant only for Schema "properties" definitions. Declares the property as + // "read only". This means that it MAY be sent as part of a response but MUST + // NOT be sent as part of the request. Properties marked as readOnly being + // true SHOULD NOT be in the required list of the defined schema. Default + // value is false. + ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + // Additional external documentation for this schema. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + // A free-form property to include an example of an instance for this schema in JSON. + // This is copied verbatim to the output. + Example string `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"` +} + +func (x *Schema) Reset() { + *x = Schema{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema) ProtoMessage() {} + +func (x *Schema) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema.ProtoReflect.Descriptor instead. +func (*Schema) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{8} +} + +func (x *Schema) GetJsonSchema() *JSONSchema { + if x != nil { + return x.JsonSchema + } + return nil +} + +func (x *Schema) GetDiscriminator() string { + if x != nil { + return x.Discriminator + } + return "" +} + +func (x *Schema) GetReadOnly() bool { + if x != nil { + return x.ReadOnly + } + return false +} + +func (x *Schema) GetExternalDocs() *ExternalDocumentation { + if x != nil { + return x.ExternalDocs + } + return nil +} + +func (x *Schema) GetExample() string { + if x != nil { + return x.Example + } + return "" +} + +// `JSONSchema` represents properties from JSON Schema taken, and as used, in +// the OpenAPI v2 spec. +// +// This includes changes made by OpenAPI v2. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject +// +// See also: https://cswr.github.io/JsonSchema/spec/basic_types/, +// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json +// +// Example: +// +// message SimpleMessage { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { +// json_schema: { +// title: "SimpleMessage" +// description: "A simple message." +// required: ["id"] +// } +// }; +// +// // Id represents the message identifier. +// string id = 1; [ +// (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { +// {description: "The unique identifier of the simple message." +// }]; +// } +// +type JSONSchema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Ref is used to define an external reference to include in the message. + // This could be a fully qualified proto message reference, and that type must + // be imported into the protofile. If no message is identified, the Ref will + // be used verbatim in the output. + // For example: + // `ref: ".google.protobuf.Timestamp"`. + Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` + // The title of the schema. + Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` + // A short description of the schema. + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + Default string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"` + ReadOnly bool `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + // A free-form property to include a JSON example of this field. This is copied + // verbatim to the output swagger.json. Quotes must be escaped. + // This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject + Example string `protobuf:"bytes,9,opt,name=example,proto3" json:"example,omitempty"` + MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"` + // Maximum represents an inclusive upper limit for a numeric instance. The + // value of MUST be a number, + Maximum float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"` + // minimum represents an inclusive lower limit for a numeric instance. The + // value of MUST be a number, + Minimum float64 `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"` + MaxLength uint64 `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` + MinLength uint64 `protobuf:"varint,16,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,17,opt,name=pattern,proto3" json:"pattern,omitempty"` + MaxItems uint64 `protobuf:"varint,20,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"` + MinItems uint64 `protobuf:"varint,21,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,22,opt,name=unique_items,json=uniqueItems,proto3" json:"unique_items,omitempty"` + MaxProperties uint64 `protobuf:"varint,24,opt,name=max_properties,json=maxProperties,proto3" json:"max_properties,omitempty"` + MinProperties uint64 `protobuf:"varint,25,opt,name=min_properties,json=minProperties,proto3" json:"min_properties,omitempty"` + Required []string `protobuf:"bytes,26,rep,name=required,proto3" json:"required,omitempty"` + // Items in 'array' must be unique. + Array []string `protobuf:"bytes,34,rep,name=array,proto3" json:"array,omitempty"` + Type []JSONSchema_JSONSchemaSimpleTypes `protobuf:"varint,35,rep,packed,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.JSONSchema_JSONSchemaSimpleTypes" json:"type,omitempty"` + // `Format` + Format string `protobuf:"bytes,36,opt,name=format,proto3" json:"format,omitempty"` + // Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1 + Enum []string `protobuf:"bytes,46,rep,name=enum,proto3" json:"enum,omitempty"` +} + +func (x *JSONSchema) Reset() { + *x = JSONSchema{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JSONSchema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JSONSchema) ProtoMessage() {} + +func (x *JSONSchema) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use JSONSchema.ProtoReflect.Descriptor instead. +func (*JSONSchema) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{9} +} + +func (x *JSONSchema) GetRef() string { + if x != nil { + return x.Ref + } + return "" +} + +func (x *JSONSchema) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *JSONSchema) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *JSONSchema) GetDefault() string { + if x != nil { + return x.Default + } + return "" +} + +func (x *JSONSchema) GetReadOnly() bool { + if x != nil { + return x.ReadOnly + } + return false +} + +func (x *JSONSchema) GetExample() string { + if x != nil { + return x.Example + } + return "" +} + +func (x *JSONSchema) GetMultipleOf() float64 { + if x != nil { + return x.MultipleOf + } + return 0 +} + +func (x *JSONSchema) GetMaximum() float64 { + if x != nil { + return x.Maximum + } + return 0 +} + +func (x *JSONSchema) GetExclusiveMaximum() bool { + if x != nil { + return x.ExclusiveMaximum + } + return false +} + +func (x *JSONSchema) GetMinimum() float64 { + if x != nil { + return x.Minimum + } + return 0 +} + +func (x *JSONSchema) GetExclusiveMinimum() bool { + if x != nil { + return x.ExclusiveMinimum + } + return false +} + +func (x *JSONSchema) GetMaxLength() uint64 { + if x != nil { + return x.MaxLength + } + return 0 +} + +func (x *JSONSchema) GetMinLength() uint64 { + if x != nil { + return x.MinLength + } + return 0 +} + +func (x *JSONSchema) GetPattern() string { + if x != nil { + return x.Pattern + } + return "" +} + +func (x *JSONSchema) GetMaxItems() uint64 { + if x != nil { + return x.MaxItems + } + return 0 +} + +func (x *JSONSchema) GetMinItems() uint64 { + if x != nil { + return x.MinItems + } + return 0 +} + +func (x *JSONSchema) GetUniqueItems() bool { + if x != nil { + return x.UniqueItems + } + return false +} + +func (x *JSONSchema) GetMaxProperties() uint64 { + if x != nil { + return x.MaxProperties + } + return 0 +} + +func (x *JSONSchema) GetMinProperties() uint64 { + if x != nil { + return x.MinProperties + } + return 0 +} + +func (x *JSONSchema) GetRequired() []string { + if x != nil { + return x.Required + } + return nil +} + +func (x *JSONSchema) GetArray() []string { + if x != nil { + return x.Array + } + return nil +} + +func (x *JSONSchema) GetType() []JSONSchema_JSONSchemaSimpleTypes { + if x != nil { + return x.Type + } + return nil +} + +func (x *JSONSchema) GetFormat() string { + if x != nil { + return x.Format + } + return "" +} + +func (x *JSONSchema) GetEnum() []string { + if x != nil { + return x.Enum + } + return nil +} + +// `Tag` is a representation of OpenAPI v2 specification's Tag object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject +// +type Tag struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A short description for the tag. GFM syntax can be used for rich text + // representation. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // Additional external documentation for this tag. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` +} + +func (x *Tag) Reset() { + *x = Tag{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Tag) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Tag) ProtoMessage() {} + +func (x *Tag) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Tag.ProtoReflect.Descriptor instead. +func (*Tag) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{10} +} + +func (x *Tag) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Tag) GetExternalDocs() *ExternalDocumentation { + if x != nil { + return x.ExternalDocs + } + return nil +} + +// `SecurityDefinitions` is a representation of OpenAPI v2 specification's +// Security Definitions object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject +// +// A declaration of the security schemes available to be used in the +// specification. This does not enforce the security schemes on the operations +// and only serves to provide the relevant details for each scheme. +type SecurityDefinitions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A single security scheme definition, mapping a "name" to the scheme it + // defines. + Security map[string]*SecurityScheme `protobuf:"bytes,1,rep,name=security,proto3" json:"security,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SecurityDefinitions) Reset() { + *x = SecurityDefinitions{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecurityDefinitions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityDefinitions) ProtoMessage() {} + +func (x *SecurityDefinitions) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityDefinitions.ProtoReflect.Descriptor instead. +func (*SecurityDefinitions) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11} +} + +func (x *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme { + if x != nil { + return x.Security + } + return nil +} + +// `SecurityScheme` is a representation of OpenAPI v2 specification's +// Security Scheme object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject +// +// Allows the definition of a security scheme that can be used by the +// operations. Supported schemes are basic authentication, an API key (either as +// a header or as a query parameter) and OAuth2's common flows (implicit, +// password, application and access code). +type SecurityScheme struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The type of the security scheme. Valid values are "basic", + // "apiKey" or "oauth2". + Type SecurityScheme_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Type" json:"type,omitempty"` + // A short description for security scheme. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // The name of the header or query parameter to be used. + // Valid for apiKey. + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + // The location of the API key. Valid values are "query" or + // "header". + // Valid for apiKey. + In SecurityScheme_In `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_In" json:"in,omitempty"` + // The flow used by the OAuth2 security scheme. Valid values are + // "implicit", "password", "application" or "accessCode". + // Valid for oauth2. + Flow SecurityScheme_Flow `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Flow" json:"flow,omitempty"` + // The authorization URL to be used for this flow. This SHOULD be in + // the form of a URL. + // Valid for oauth2/implicit and oauth2/accessCode. + AuthorizationUrl string `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"` + // The token URL to be used for this flow. This SHOULD be in the + // form of a URL. + // Valid for oauth2/password, oauth2/application and oauth2/accessCode. + TokenUrl string `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"` + // The available scopes for the OAuth2 security scheme. + // Valid for oauth2. + Scopes *Scopes `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"` + Extensions map[string]*_struct.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SecurityScheme) Reset() { + *x = SecurityScheme{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecurityScheme) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityScheme) ProtoMessage() {} + +func (x *SecurityScheme) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityScheme.ProtoReflect.Descriptor instead. +func (*SecurityScheme) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12} +} + +func (x *SecurityScheme) GetType() SecurityScheme_Type { + if x != nil { + return x.Type + } + return SecurityScheme_TYPE_INVALID +} + +func (x *SecurityScheme) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *SecurityScheme) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SecurityScheme) GetIn() SecurityScheme_In { + if x != nil { + return x.In + } + return SecurityScheme_IN_INVALID +} + +func (x *SecurityScheme) GetFlow() SecurityScheme_Flow { + if x != nil { + return x.Flow + } + return SecurityScheme_FLOW_INVALID +} + +func (x *SecurityScheme) GetAuthorizationUrl() string { + if x != nil { + return x.AuthorizationUrl + } + return "" +} + +func (x *SecurityScheme) GetTokenUrl() string { + if x != nil { + return x.TokenUrl + } + return "" +} + +func (x *SecurityScheme) GetScopes() *Scopes { + if x != nil { + return x.Scopes + } + return nil +} + +func (x *SecurityScheme) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `SecurityRequirement` is a representation of OpenAPI v2 specification's +// Security Requirement object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject +// +// Lists the required security schemes to execute this operation. The object can +// have multiple security schemes declared in it which are all required (that +// is, there is a logical AND between the schemes). +// +// The name used for each property MUST correspond to a security scheme +// declared in the Security Definitions. +type SecurityRequirement struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Each name must correspond to a security scheme which is declared in + // the Security Definitions. If the security scheme is of type "oauth2", + // then the value is a list of scope names required for the execution. + // For other security scheme types, the array MUST be empty. + SecurityRequirement map[string]*SecurityRequirement_SecurityRequirementValue `protobuf:"bytes,1,rep,name=security_requirement,json=securityRequirement,proto3" json:"security_requirement,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SecurityRequirement) Reset() { + *x = SecurityRequirement{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecurityRequirement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityRequirement) ProtoMessage() {} + +func (x *SecurityRequirement) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityRequirement.ProtoReflect.Descriptor instead. +func (*SecurityRequirement) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{13} +} + +func (x *SecurityRequirement) GetSecurityRequirement() map[string]*SecurityRequirement_SecurityRequirementValue { + if x != nil { + return x.SecurityRequirement + } + return nil +} + +// `Scopes` is a representation of OpenAPI v2 specification's Scopes object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject +// +// Lists the available scopes for an OAuth2 security scheme. +type Scopes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Maps between a name of a scope to a short description of it (as the value + // of the property). + Scope map[string]string `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Scopes) Reset() { + *x = Scopes{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Scopes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Scopes) ProtoMessage() {} + +func (x *Scopes) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Scopes.ProtoReflect.Descriptor instead. +func (*Scopes) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{14} +} + +func (x *Scopes) GetScope() map[string]string { + if x != nil { + return x.Scope + } + return nil +} + +// If the security scheme is of type "oauth2", then the value is a list of +// scope names required for the execution. For other security scheme types, +// the array MUST be empty. +type SecurityRequirement_SecurityRequirementValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Scope []string `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty"` +} + +func (x *SecurityRequirement_SecurityRequirementValue) Reset() { + *x = SecurityRequirement_SecurityRequirementValue{} + if protoimpl.UnsafeEnabled { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecurityRequirement_SecurityRequirementValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityRequirement_SecurityRequirementValue) ProtoMessage() {} + +func (x *SecurityRequirement_SecurityRequirementValue) ProtoReflect() protoreflect.Message { + mi := &file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityRequirement_SecurityRequirementValue.ProtoReflect.Descriptor instead. +func (*SecurityRequirement_SecurityRequirementValue) Descriptor() ([]byte, []int) { + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{13, 0} +} + +func (x *SecurityRequirement_SecurityRequirementValue) GetScope() []string { + if x != nil { + return x.Scope + } + return nil +} + +var File_protoc_gen_openapiv2_options_openapiv2_proto protoreflect.FileDescriptor + +var file_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ + 0x0a, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, + 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf5, 0x07, 0x0a, 0x07, 0x53, 0x77, 0x61, 0x67, + 0x67, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x12, 0x43, 0x0a, + 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, + 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x50, + 0x61, 0x74, 0x68, 0x12, 0x4b, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, + 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, + 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, + 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x12, 0x5f, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x71, 0x0a, 0x14, 0x73, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x13, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5a, 0x0a, 0x08, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, + 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x65, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x12, + 0x62, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0f, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x1a, 0x71, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x49, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, + 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, + 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, 0x22, + 0xff, 0x06, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, + 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, + 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x44, 0x6f, 0x63, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x18, + 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x12, + 0x61, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, + 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x18, 0x0a, 0x20, + 0x03, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x12, + 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, + 0x5a, 0x0a, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x0c, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x52, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x64, 0x0a, 0x0a, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x1a, 0x71, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x49, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x08, 0x10, + 0x09, 0x22, 0xd8, 0x01, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x4a, 0x04, + 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, + 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, + 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x4a, 0x04, 0x08, 0x0c, 0x10, 0x0d, 0x4a, 0x04, + 0x08, 0x0e, 0x10, 0x0f, 0x4a, 0x04, 0x08, 0x0f, 0x10, 0x10, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, + 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x22, 0x9a, 0x05, 0x0a, + 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x06, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x5a, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x12, 0x5d, 0x0a, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x12, 0x63, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x6d, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3b, 0x0a, 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd6, 0x03, 0x0a, 0x04, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x65, + 0x72, 0x6d, 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x4f, 0x66, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x63, 0x74, 0x12, 0x4c, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x0a, 0x65, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, + 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x2e, + 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x45, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x45, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x75, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x2f, 0x0a, 0x07, 0x4c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x4b, 0x0a, 0x15, 0x45, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0xaa, 0x02, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x12, 0x56, 0x0a, 0x0b, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0a, + 0x6a, 0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x69, + 0x73, 0x63, 0x72, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x63, 0x72, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, + 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x65, 0x0a, + 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x44, 0x6f, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x4a, 0x04, + 0x08, 0x04, 0x10, 0x05, 0x22, 0xdf, 0x07, 0x0a, 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, + 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, + 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x0a, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4f, 0x66, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, + 0x52, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, + 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, + 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, + 0x6d, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, + 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, + 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, + 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x1d, 0x0a, + 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x6d, 0x61, 0x78, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, + 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x09, 0x6d, 0x69, 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, + 0x6d, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, + 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, + 0x15, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, + 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, + 0x6d, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x69, 0x65, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x50, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, + 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, + 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x1a, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x12, 0x5f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0e, + 0x32, 0x4b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, + 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x24, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, + 0x6e, 0x75, 0x6d, 0x18, 0x2e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x65, 0x6e, 0x75, 0x6d, 0x22, + 0x77, 0x0a, 0x15, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x01, + 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, 0x0b, 0x0a, + 0x07, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x55, + 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x05, + 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x06, 0x12, 0x0a, 0x0a, 0x06, + 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, + 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, + 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x1b, + 0x10, 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e, 0x4a, 0x04, + 0x08, 0x1e, 0x10, 0x22, 0x4a, 0x04, 0x08, 0x25, 0x10, 0x2a, 0x4a, 0x04, 0x08, 0x2a, 0x10, 0x2b, + 0x4a, 0x04, 0x08, 0x2b, 0x10, 0x2e, 0x22, 0x94, 0x01, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x65, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xf7, 0x01, + 0x0a, 0x13, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x68, 0x0a, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x1a, + 0x76, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x4f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x39, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xff, 0x06, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x52, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, + 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4c, 0x0a, 0x02, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x3c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x2e, 0x49, 0x6e, 0x52, 0x02, + 0x69, 0x6e, 0x12, 0x52, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x2e, 0x46, 0x6c, 0x6f, 0x77, + 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x10, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x75, 0x72, 0x6c, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x72, 0x6c, + 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x6f, + 0x70, 0x65, 0x73, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x69, 0x0a, 0x0a, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x49, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4b, 0x0a, + 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, + 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x42, 0x41, 0x53, 0x49, 0x43, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x41, 0x50, 0x49, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x4f, 0x41, 0x55, 0x54, 0x48, 0x32, 0x10, 0x03, 0x22, 0x31, 0x0a, 0x02, 0x49, 0x6e, + 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4e, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, + 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x10, 0x01, 0x12, 0x0d, + 0x0a, 0x09, 0x49, 0x4e, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x02, 0x22, 0x6a, 0x0a, + 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x10, 0x0a, 0x0c, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x4e, + 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x57, 0x5f, + 0x49, 0x4d, 0x50, 0x4c, 0x49, 0x43, 0x49, 0x54, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x4c, + 0x4f, 0x57, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x10, 0x02, 0x12, 0x14, 0x0a, + 0x10, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x41, 0x50, 0x50, 0x4c, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x41, 0x43, 0x43, 0x45, + 0x53, 0x53, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x04, 0x22, 0xf6, 0x02, 0x0a, 0x13, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x8a, 0x01, 0x0a, 0x14, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x57, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x73, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x30, + 0x0a, 0x18, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, + 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, + 0x1a, 0x9f, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x6d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x57, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, + 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x96, 0x01, 0x0a, 0x06, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x52, 0x0a, + 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, + 0x53, 0x63, 0x6f, 0x70, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, + 0x65, 0x1a, 0x38, 0x0a, 0x0a, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x3b, 0x0a, 0x06, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, + 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x02, 0x12, 0x06, 0x0a, 0x02, 0x57, 0x53, 0x10, 0x03, 0x12, + 0x07, 0x0a, 0x03, 0x57, 0x53, 0x53, 0x10, 0x04, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, + 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescOnce sync.Once + file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescData = file_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc +) + +func file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP() []byte { + file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescOnce.Do(func() { + file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescData = protoimpl.X.CompressGZIP(file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescData) + }) + return file_protoc_gen_openapiv2_options_openapiv2_proto_rawDescData +} + +var file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes = make([]protoimpl.MessageInfo, 28) +var file_protoc_gen_openapiv2_options_openapiv2_proto_goTypes = []interface{}{ + (Scheme)(0), // 0: grpc.gateway.protoc_gen_openapiv2.options.Scheme + (JSONSchema_JSONSchemaSimpleTypes)(0), // 1: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes + (SecurityScheme_Type)(0), // 2: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Type + (SecurityScheme_In)(0), // 3: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.In + (SecurityScheme_Flow)(0), // 4: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow + (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger + (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation + (*Header)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Header + (*Response)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Response + (*Info)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.Info + (*Contact)(nil), // 10: grpc.gateway.protoc_gen_openapiv2.options.Contact + (*License)(nil), // 11: grpc.gateway.protoc_gen_openapiv2.options.License + (*ExternalDocumentation)(nil), // 12: grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + (*Schema)(nil), // 13: grpc.gateway.protoc_gen_openapiv2.options.Schema + (*JSONSchema)(nil), // 14: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + (*Tag)(nil), // 15: grpc.gateway.protoc_gen_openapiv2.options.Tag + (*SecurityDefinitions)(nil), // 16: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions + (*SecurityScheme)(nil), // 17: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme + (*SecurityRequirement)(nil), // 18: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + (*Scopes)(nil), // 19: grpc.gateway.protoc_gen_openapiv2.options.Scopes + nil, // 20: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry + nil, // 21: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry + nil, // 22: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry + nil, // 23: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry + nil, // 24: grpc.gateway.protoc_gen_openapiv2.options.Response.HeadersEntry + nil, // 25: grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry + nil, // 26: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry + nil, // 27: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry + nil, // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry + nil, // 29: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry + (*SecurityRequirement_SecurityRequirementValue)(nil), // 30: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue + nil, // 31: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry + nil, // 32: grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry + (*_struct.Value)(nil), // 33: google.protobuf.Value +} +var file_protoc_gen_openapiv2_options_openapiv2_proto_depIdxs = []int32{ + 9, // 0: grpc.gateway.protoc_gen_openapiv2.options.Swagger.info:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info + 0, // 1: grpc.gateway.protoc_gen_openapiv2.options.Swagger.schemes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scheme + 20, // 2: grpc.gateway.protoc_gen_openapiv2.options.Swagger.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry + 16, // 3: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security_definitions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions + 18, // 4: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + 12, // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 21, // 6: grpc.gateway.protoc_gen_openapiv2.options.Swagger.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry + 12, // 7: grpc.gateway.protoc_gen_openapiv2.options.Operation.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 22, // 8: grpc.gateway.protoc_gen_openapiv2.options.Operation.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry + 0, // 9: grpc.gateway.protoc_gen_openapiv2.options.Operation.schemes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scheme + 18, // 10: grpc.gateway.protoc_gen_openapiv2.options.Operation.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + 23, // 11: grpc.gateway.protoc_gen_openapiv2.options.Operation.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry + 13, // 12: grpc.gateway.protoc_gen_openapiv2.options.Response.schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema + 24, // 13: grpc.gateway.protoc_gen_openapiv2.options.Response.headers:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.HeadersEntry + 25, // 14: grpc.gateway.protoc_gen_openapiv2.options.Response.examples:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry + 26, // 15: grpc.gateway.protoc_gen_openapiv2.options.Response.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry + 10, // 16: grpc.gateway.protoc_gen_openapiv2.options.Info.contact:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Contact + 11, // 17: grpc.gateway.protoc_gen_openapiv2.options.Info.license:type_name -> grpc.gateway.protoc_gen_openapiv2.options.License + 27, // 18: grpc.gateway.protoc_gen_openapiv2.options.Info.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry + 14, // 19: grpc.gateway.protoc_gen_openapiv2.options.Schema.json_schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + 12, // 20: grpc.gateway.protoc_gen_openapiv2.options.Schema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 1, // 21: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes + 12, // 22: grpc.gateway.protoc_gen_openapiv2.options.Tag.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 28, // 23: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry + 2, // 24: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Type + 3, // 25: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.in:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.In + 4, // 26: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.flow:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow + 19, // 27: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.scopes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes + 29, // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry + 31, // 29: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.security_requirement:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry + 32, // 30: grpc.gateway.protoc_gen_openapiv2.options.Scopes.scope:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry + 8, // 31: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response + 33, // 32: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry.value:type_name -> google.protobuf.Value + 8, // 33: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response + 33, // 34: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry.value:type_name -> google.protobuf.Value + 7, // 35: grpc.gateway.protoc_gen_openapiv2.options.Response.HeadersEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Header + 33, // 36: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry.value:type_name -> google.protobuf.Value + 33, // 37: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry.value:type_name -> google.protobuf.Value + 17, // 38: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme + 33, // 39: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry.value:type_name -> google.protobuf.Value + 30, // 40: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue + 41, // [41:41] is the sub-list for method output_type + 41, // [41:41] is the sub-list for method input_type + 41, // [41:41] is the sub-list for extension type_name + 41, // [41:41] is the sub-list for extension extendee + 0, // [0:41] is the sub-list for field type_name +} + +func init() { file_protoc_gen_openapiv2_options_openapiv2_proto_init() } +func file_protoc_gen_openapiv2_options_openapiv2_proto_init() { + if File_protoc_gen_openapiv2_options_openapiv2_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Swagger); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Operation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Header); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Info); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Contact); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*License); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExternalDocumentation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JSONSchema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Tag); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityDefinitions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityScheme); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityRequirement); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Scopes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityRequirement_SecurityRequirementValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc, + NumEnums: 5, + NumMessages: 28, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_protoc_gen_openapiv2_options_openapiv2_proto_goTypes, + DependencyIndexes: file_protoc_gen_openapiv2_options_openapiv2_proto_depIdxs, + EnumInfos: file_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes, + MessageInfos: file_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes, + }.Build() + File_protoc_gen_openapiv2_options_openapiv2_proto = out.File + file_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = nil + file_protoc_gen_openapiv2_options_openapiv2_proto_goTypes = nil + file_protoc_gen_openapiv2_options_openapiv2_proto_depIdxs = nil +} diff --git a/third_party/proto/protoc-gen-openapiv2/options/openapiv2.proto b/third_party/proto/protoc-gen-openapiv2/options/openapiv2.proto new file mode 100644 index 00000000000..7be1fb572c7 --- /dev/null +++ b/third_party/proto/protoc-gen-openapiv2/options/openapiv2.proto @@ -0,0 +1,645 @@ +syntax = "proto3"; + +package grpc.gateway.protoc_gen_openapiv2.options; + +option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"; + +import "google/protobuf/struct.proto"; + +// Scheme describes the schemes supported by the OpenAPI Swagger +// and Operation objects. +enum Scheme { + UNKNOWN = 0; + HTTP = 1; + HTTPS = 2; + WS = 3; + WSS = 4; +} + +// `Swagger` is a representation of OpenAPI v2 specification's Swagger object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// title: "Echo API"; +// version: "1.0"; +// description: "; +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// }; +// schemes: HTTPS; +// consumes: "application/json"; +// produces: "application/json"; +// }; +// +message Swagger { + // Specifies the OpenAPI Specification version being used. It can be + // used by the OpenAPI UI and other clients to interpret the API listing. The + // value MUST be "2.0". + string swagger = 1; + // Provides metadata about the API. The metadata can be used by the + // clients if needed. + Info info = 2; + // The host (name or ip) serving the API. This MUST be the host only and does + // not include the scheme nor sub-paths. It MAY include a port. If the host is + // not included, the host serving the documentation is to be used (including + // the port). The host does not support path templating. + string host = 3; + // The base path on which the API is served, which is relative to the host. If + // it is not included, the API is served directly under the host. The value + // MUST start with a leading slash (/). The basePath does not support path + // templating. + // Note that using `base_path` does not change the endpoint paths that are + // generated in the resulting OpenAPI file. If you wish to use `base_path` + // with relatively generated OpenAPI paths, the `base_path` prefix must be + // manually removed from your `google.api.http` paths and your code changed to + // serve the API from the `base_path`. + string base_path = 4; + // The transfer protocol of the API. Values MUST be from the list: "http", + // "https", "ws", "wss". If the schemes is not included, the default scheme to + // be used is the one used to access the OpenAPI definition itself. + repeated Scheme schemes = 5; + // A list of MIME types the APIs can consume. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. + repeated string consumes = 6; + // A list of MIME types the APIs can produce. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. + repeated string produces = 7; + // field 8 is reserved for 'paths'. + reserved 8; + // field 9 is reserved for 'definitions', which at this time are already + // exposed as and customizable as proto messages. + reserved 9; + // An object to hold responses that can be used across operations. This + // property does not define global responses for all operations. + map responses = 10; + // Security scheme definitions that can be used across the specification. + SecurityDefinitions security_definitions = 11; + // A declaration of which security schemes are applied for the API as a whole. + // The list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). + // Individual operations can override this definition. + repeated SecurityRequirement security = 12; + // field 13 is reserved for 'tags', which are supposed to be exposed as and + // customizable as proto services. TODO(ivucica): add processing of proto + // service objects into OpenAPI v2 Tag objects. + reserved 13; + // Additional external documentation. + ExternalDocumentation external_docs = 14; + map extensions = 15; +} + +// `Operation` is a representation of OpenAPI v2 specification's Operation object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject +// +// Example: +// +// service EchoService { +// rpc Echo(SimpleMessage) returns (SimpleMessage) { +// option (google.api.http) = { +// get: "/v1/example/echo/{id}" +// }; +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { +// summary: "Get a message."; +// operation_id: "getMessage"; +// tags: "echo"; +// responses: { +// key: "200" +// value: { +// description: "OK"; +// } +// } +// }; +// } +// } +message Operation { + // A list of tags for API documentation control. Tags can be used for logical + // grouping of operations by resources or any other qualifier. + repeated string tags = 1; + // A short summary of what the operation does. For maximum readability in the + // swagger-ui, this field SHOULD be less than 120 characters. + string summary = 2; + // A verbose explanation of the operation behavior. GFM syntax can be used for + // rich text representation. + string description = 3; + // Additional external documentation for this operation. + ExternalDocumentation external_docs = 4; + // Unique string used to identify the operation. The id MUST be unique among + // all operations described in the API. Tools and libraries MAY use the + // operationId to uniquely identify an operation, therefore, it is recommended + // to follow common programming naming conventions. + string operation_id = 5; + // A list of MIME types the operation can consume. This overrides the consumes + // definition at the OpenAPI Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. + repeated string consumes = 6; + // A list of MIME types the operation can produce. This overrides the produces + // definition at the OpenAPI Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. + repeated string produces = 7; + // field 8 is reserved for 'parameters'. + reserved 8; + // The list of possible responses as they are returned from executing this + // operation. + map responses = 9; + // The transfer protocol for the operation. Values MUST be from the list: + // "http", "https", "ws", "wss". The value overrides the OpenAPI Object + // schemes definition. + repeated Scheme schemes = 10; + // Declares this operation to be deprecated. Usage of the declared operation + // should be refrained. Default value is false. + bool deprecated = 11; + // A declaration of which security schemes are applied for this operation. The + // list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). This + // definition overrides any declared top-level security. To remove a top-level + // security declaration, an empty array can be used. + repeated SecurityRequirement security = 12; + map extensions = 13; +} + +// `Header` is a representation of OpenAPI v2 specification's Header object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject +// +message Header { + // `Description` is a short description of the header. + string description = 1; + // The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported. + string type = 2; + // `Format` The extending format for the previously mentioned type. + string format = 3; + // field 4 is reserved for 'items', but in OpenAPI-specific way. + reserved 4; + // field 5 is reserved `Collection Format` Determines the format of the array if type array is used. + reserved 5; + // `Default` Declares the value of the header that the server will use if none is provided. + // See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. + // Unlike JSON Schema this value MUST conform to the defined type for the header. + string default = 6; + // field 7 is reserved for 'maximum'. + reserved 7; + // field 8 is reserved for 'exclusiveMaximum'. + reserved 8; + // field 9 is reserved for 'minimum'. + reserved 9; + // field 10 is reserved for 'exclusiveMinimum'. + reserved 10; + // field 11 is reserved for 'maxLength'. + reserved 11; + // field 12 is reserved for 'minLength'. + reserved 12; + // 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3. + string pattern = 13; + // field 14 is reserved for 'maxItems'. + reserved 14; + // field 15 is reserved for 'minItems'. + reserved 15; + // field 16 is reserved for 'uniqueItems'. + reserved 16; + // field 17 is reserved for 'enum'. + reserved 17; + // field 18 is reserved for 'multipleOf'. + reserved 18; +} + +// `Response` is a representation of OpenAPI v2 specification's Response object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject +// +message Response { + // `Description` is a short description of the response. + // GFM syntax can be used for rich text representation. + string description = 1; + // `Schema` optionally defines the structure of the response. + // If `Schema` is not provided, it means there is no content to the response. + Schema schema = 2; + // `Headers` A list of headers that are sent with the response. + // `Header` name is expected to be a string in the canonical format of the MIME header key + // See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey + map headers = 3; + // `Examples` gives per-mimetype response examples. + // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object + map examples = 4; + map extensions = 5; +} + +// `Info` is a representation of OpenAPI v2 specification's Info object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// title: "Echo API"; +// version: "1.0"; +// description: "; +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// }; +// ... +// }; +// +message Info { + // The title of the application. + string title = 1; + // A short description of the application. GFM syntax can be used for rich + // text representation. + string description = 2; + // The Terms of Service for the API. + string terms_of_service = 3; + // The contact information for the exposed API. + Contact contact = 4; + // The license information for the exposed API. + License license = 5; + // Provides the version of the application API (not to be confused + // with the specification version). + string version = 6; + map extensions = 7; +} + +// `Contact` is a representation of OpenAPI v2 specification's Contact object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// ... +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// ... +// }; +// ... +// }; +// +message Contact { + // The identifying name of the contact person/organization. + string name = 1; + // The URL pointing to the contact information. MUST be in the format of a + // URL. + string url = 2; + // The email address of the contact person/organization. MUST be in the format + // of an email address. + string email = 3; +} + +// `License` is a representation of OpenAPI v2 specification's License object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// ... +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// ... +// }; +// ... +// }; +// +message License { + // The license name used for the API. + string name = 1; + // A URL to the license used for the API. MUST be in the format of a URL. + string url = 2; +} + +// `ExternalDocumentation` is a representation of OpenAPI v2 specification's +// ExternalDocumentation object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// ... +// external_docs: { +// description: "More about gRPC-Gateway"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// } +// ... +// }; +// +message ExternalDocumentation { + // A short description of the target documentation. GFM syntax can be used for + // rich text representation. + string description = 1; + // The URL for the target documentation. Value MUST be in the format + // of a URL. + string url = 2; +} + +// `Schema` is a representation of OpenAPI v2 specification's Schema object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject +// +message Schema { + JSONSchema json_schema = 1; + // Adds support for polymorphism. The discriminator is the schema property + // name that is used to differentiate between other schema that inherit this + // schema. The property name used MUST be defined at this schema and it MUST + // be in the required property list. When used, the value MUST be the name of + // this schema or any schema that inherits it. + string discriminator = 2; + // Relevant only for Schema "properties" definitions. Declares the property as + // "read only". This means that it MAY be sent as part of a response but MUST + // NOT be sent as part of the request. Properties marked as readOnly being + // true SHOULD NOT be in the required list of the defined schema. Default + // value is false. + bool read_only = 3; + // field 4 is reserved for 'xml'. + reserved 4; + // Additional external documentation for this schema. + ExternalDocumentation external_docs = 5; + // A free-form property to include an example of an instance for this schema in JSON. + // This is copied verbatim to the output. + string example = 6; +} + +// `JSONSchema` represents properties from JSON Schema taken, and as used, in +// the OpenAPI v2 spec. +// +// This includes changes made by OpenAPI v2. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject +// +// See also: https://cswr.github.io/JsonSchema/spec/basic_types/, +// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json +// +// Example: +// +// message SimpleMessage { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { +// json_schema: { +// title: "SimpleMessage" +// description: "A simple message." +// required: ["id"] +// } +// }; +// +// // Id represents the message identifier. +// string id = 1; [ +// (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { +// {description: "The unique identifier of the simple message." +// }]; +// } +// +message JSONSchema { + // field 1 is reserved for '$id', omitted from OpenAPI v2. + reserved 1; + // field 2 is reserved for '$schema', omitted from OpenAPI v2. + reserved 2; + // Ref is used to define an external reference to include in the message. + // This could be a fully qualified proto message reference, and that type must + // be imported into the protofile. If no message is identified, the Ref will + // be used verbatim in the output. + // For example: + // `ref: ".google.protobuf.Timestamp"`. + string ref = 3; + // field 4 is reserved for '$comment', omitted from OpenAPI v2. + reserved 4; + // The title of the schema. + string title = 5; + // A short description of the schema. + string description = 6; + string default = 7; + bool read_only = 8; + // A free-form property to include a JSON example of this field. This is copied + // verbatim to the output swagger.json. Quotes must be escaped. + // This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject + string example = 9; + double multiple_of = 10; + // Maximum represents an inclusive upper limit for a numeric instance. The + // value of MUST be a number, + double maximum = 11; + bool exclusive_maximum = 12; + // minimum represents an inclusive lower limit for a numeric instance. The + // value of MUST be a number, + double minimum = 13; + bool exclusive_minimum = 14; + uint64 max_length = 15; + uint64 min_length = 16; + string pattern = 17; + // field 18 is reserved for 'additionalItems', omitted from OpenAPI v2. + reserved 18; + // field 19 is reserved for 'items', but in OpenAPI-specific way. + // TODO(ivucica): add 'items'? + reserved 19; + uint64 max_items = 20; + uint64 min_items = 21; + bool unique_items = 22; + // field 23 is reserved for 'contains', omitted from OpenAPI v2. + reserved 23; + uint64 max_properties = 24; + uint64 min_properties = 25; + repeated string required = 26; + // field 27 is reserved for 'additionalProperties', but in OpenAPI-specific + // way. TODO(ivucica): add 'additionalProperties'? + reserved 27; + // field 28 is reserved for 'definitions', omitted from OpenAPI v2. + reserved 28; + // field 29 is reserved for 'properties', but in OpenAPI-specific way. + // TODO(ivucica): add 'additionalProperties'? + reserved 29; + // following fields are reserved, as the properties have been omitted from + // OpenAPI v2: + // patternProperties, dependencies, propertyNames, const + reserved 30 to 33; + // Items in 'array' must be unique. + repeated string array = 34; + + enum JSONSchemaSimpleTypes { + UNKNOWN = 0; + ARRAY = 1; + BOOLEAN = 2; + INTEGER = 3; + NULL = 4; + NUMBER = 5; + OBJECT = 6; + STRING = 7; + } + + repeated JSONSchemaSimpleTypes type = 35; + // `Format` + string format = 36; + // following fields are reserved, as the properties have been omitted from + // OpenAPI v2: contentMediaType, contentEncoding, if, then, else + reserved 37 to 41; + // field 42 is reserved for 'allOf', but in OpenAPI-specific way. + // TODO(ivucica): add 'allOf'? + reserved 42; + // following fields are reserved, as the properties have been omitted from + // OpenAPI v2: + // anyOf, oneOf, not + reserved 43 to 45; + // Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1 + repeated string enum = 46; +} + +// `Tag` is a representation of OpenAPI v2 specification's Tag object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject +// +message Tag { + // field 1 is reserved for 'name'. In our generator, this is (to be) extracted + // from the name of proto service, and thus not exposed to the user, as + // changing tag object's name would break the link to the references to the + // tag in individual operation specifications. + // + // TODO(ivucica): Add 'name' property. Use it to allow override of the name of + // global Tag object, then use that name to reference the tag throughout the + // OpenAPI file. + reserved 1; + // A short description for the tag. GFM syntax can be used for rich text + // representation. + string description = 2; + // Additional external documentation for this tag. + ExternalDocumentation external_docs = 3; +} + +// `SecurityDefinitions` is a representation of OpenAPI v2 specification's +// Security Definitions object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject +// +// A declaration of the security schemes available to be used in the +// specification. This does not enforce the security schemes on the operations +// and only serves to provide the relevant details for each scheme. +message SecurityDefinitions { + // A single security scheme definition, mapping a "name" to the scheme it + // defines. + map security = 1; +} + +// `SecurityScheme` is a representation of OpenAPI v2 specification's +// Security Scheme object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject +// +// Allows the definition of a security scheme that can be used by the +// operations. Supported schemes are basic authentication, an API key (either as +// a header or as a query parameter) and OAuth2's common flows (implicit, +// password, application and access code). +message SecurityScheme { + // The type of the security scheme. Valid values are "basic", + // "apiKey" or "oauth2". + enum Type { + TYPE_INVALID = 0; + TYPE_BASIC = 1; + TYPE_API_KEY = 2; + TYPE_OAUTH2 = 3; + } + + // The location of the API key. Valid values are "query" or "header". + enum In { + IN_INVALID = 0; + IN_QUERY = 1; + IN_HEADER = 2; + } + + // The flow used by the OAuth2 security scheme. Valid values are + // "implicit", "password", "application" or "accessCode". + enum Flow { + FLOW_INVALID = 0; + FLOW_IMPLICIT = 1; + FLOW_PASSWORD = 2; + FLOW_APPLICATION = 3; + FLOW_ACCESS_CODE = 4; + } + + // The type of the security scheme. Valid values are "basic", + // "apiKey" or "oauth2". + Type type = 1; + // A short description for security scheme. + string description = 2; + // The name of the header or query parameter to be used. + // Valid for apiKey. + string name = 3; + // The location of the API key. Valid values are "query" or + // "header". + // Valid for apiKey. + In in = 4; + // The flow used by the OAuth2 security scheme. Valid values are + // "implicit", "password", "application" or "accessCode". + // Valid for oauth2. + Flow flow = 5; + // The authorization URL to be used for this flow. This SHOULD be in + // the form of a URL. + // Valid for oauth2/implicit and oauth2/accessCode. + string authorization_url = 6; + // The token URL to be used for this flow. This SHOULD be in the + // form of a URL. + // Valid for oauth2/password, oauth2/application and oauth2/accessCode. + string token_url = 7; + // The available scopes for the OAuth2 security scheme. + // Valid for oauth2. + Scopes scopes = 8; + map extensions = 9; +} + +// `SecurityRequirement` is a representation of OpenAPI v2 specification's +// Security Requirement object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject +// +// Lists the required security schemes to execute this operation. The object can +// have multiple security schemes declared in it which are all required (that +// is, there is a logical AND between the schemes). +// +// The name used for each property MUST correspond to a security scheme +// declared in the Security Definitions. +message SecurityRequirement { + // If the security scheme is of type "oauth2", then the value is a list of + // scope names required for the execution. For other security scheme types, + // the array MUST be empty. + message SecurityRequirementValue { + repeated string scope = 1; + } + // Each name must correspond to a security scheme which is declared in + // the Security Definitions. If the security scheme is of type "oauth2", + // then the value is a list of scope names required for the execution. + // For other security scheme types, the array MUST be empty. + map security_requirement = 1; +} + +// `Scopes` is a representation of OpenAPI v2 specification's Scopes object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject +// +// Lists the available scopes for an OAuth2 security scheme. +message Scopes { + // Maps between a name of a scope to a short description of it (as the value + // of the property). + map scope = 1; +} diff --git a/third_party/proto/tendermint/abci/types.proto b/third_party/proto/tendermint/abci/types.proto new file mode 100644 index 00000000000..2cbcabb29b3 --- /dev/null +++ b/third_party/proto/tendermint/abci/types.proto @@ -0,0 +1,407 @@ +syntax = "proto3"; +package tendermint.abci; + +option go_package = "github.com/tendermint/tendermint/abci/types"; + +// For more information on gogo.proto, see: +// https://github.com/gogo/protobuf/blob/master/extensions.md +import "tendermint/crypto/proof.proto"; +import "tendermint/types/types.proto"; +import "tendermint/crypto/keys.proto"; +import "tendermint/types/params.proto"; +import "google/protobuf/timestamp.proto"; +import "gogoproto/gogo.proto"; + +// This file is copied from http://github.com/tendermint/abci +// NOTE: When using custom types, mind the warnings. +// https://github.com/gogo/protobuf/blob/master/custom_types.md#warnings-and-issues + +//---------------------------------------- +// Request types + +message Request { + oneof value { + RequestEcho echo = 1; + RequestFlush flush = 2; + RequestInfo info = 3; + RequestSetOption set_option = 4; + RequestInitChain init_chain = 5; + RequestQuery query = 6; + RequestBeginBlock begin_block = 7; + RequestCheckTx check_tx = 8; + RequestDeliverTx deliver_tx = 9; + RequestEndBlock end_block = 10; + RequestCommit commit = 11; + RequestListSnapshots list_snapshots = 12; + RequestOfferSnapshot offer_snapshot = 13; + RequestLoadSnapshotChunk load_snapshot_chunk = 14; + RequestApplySnapshotChunk apply_snapshot_chunk = 15; + } +} + +message RequestEcho { + string message = 1; +} + +message RequestFlush {} + +message RequestInfo { + string version = 1; + uint64 block_version = 2; + uint64 p2p_version = 3; +} + +// nondeterministic +message RequestSetOption { + string key = 1; + string value = 2; +} + +message RequestInitChain { + google.protobuf.Timestamp time = 1 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + string chain_id = 2; + ConsensusParams consensus_params = 3; + repeated ValidatorUpdate validators = 4 [(gogoproto.nullable) = false]; + bytes app_state_bytes = 5; + int64 initial_height = 6; +} + +message RequestQuery { + bytes data = 1; + string path = 2; + int64 height = 3; + bool prove = 4; +} + +message RequestBeginBlock { + bytes hash = 1; + tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; + LastCommitInfo last_commit_info = 3 [(gogoproto.nullable) = false]; + repeated Evidence byzantine_validators = 4 [(gogoproto.nullable) = false]; +} + +enum CheckTxType { + NEW = 0 [(gogoproto.enumvalue_customname) = "New"]; + RECHECK = 1 [(gogoproto.enumvalue_customname) = "Recheck"]; +} + +message RequestCheckTx { + bytes tx = 1; + CheckTxType type = 2; +} + +message RequestDeliverTx { + bytes tx = 1; +} + +message RequestEndBlock { + int64 height = 1; +} + +message RequestCommit {} + +// lists available snapshots +message RequestListSnapshots { +} + +// offers a snapshot to the application +message RequestOfferSnapshot { + Snapshot snapshot = 1; // snapshot offered by peers + bytes app_hash = 2; // light client-verified app hash for snapshot height +} + +// loads a snapshot chunk +message RequestLoadSnapshotChunk { + uint64 height = 1; + uint32 format = 2; + uint32 chunk = 3; +} + +// Applies a snapshot chunk +message RequestApplySnapshotChunk { + uint32 index = 1; + bytes chunk = 2; + string sender = 3; +} + +//---------------------------------------- +// Response types + +message Response { + oneof value { + ResponseException exception = 1; + ResponseEcho echo = 2; + ResponseFlush flush = 3; + ResponseInfo info = 4; + ResponseSetOption set_option = 5; + ResponseInitChain init_chain = 6; + ResponseQuery query = 7; + ResponseBeginBlock begin_block = 8; + ResponseCheckTx check_tx = 9; + ResponseDeliverTx deliver_tx = 10; + ResponseEndBlock end_block = 11; + ResponseCommit commit = 12; + ResponseListSnapshots list_snapshots = 13; + ResponseOfferSnapshot offer_snapshot = 14; + ResponseLoadSnapshotChunk load_snapshot_chunk = 15; + ResponseApplySnapshotChunk apply_snapshot_chunk = 16; + } +} + +// nondeterministic +message ResponseException { + string error = 1; +} + +message ResponseEcho { + string message = 1; +} + +message ResponseFlush {} + +message ResponseInfo { + string data = 1; + + string version = 2; + uint64 app_version = 3; + + int64 last_block_height = 4; + bytes last_block_app_hash = 5; +} + +// nondeterministic +message ResponseSetOption { + uint32 code = 1; + // bytes data = 2; + string log = 3; + string info = 4; +} + +message ResponseInitChain { + ConsensusParams consensus_params = 1; + repeated ValidatorUpdate validators = 2 [(gogoproto.nullable) = false]; + bytes app_hash = 3; +} + +message ResponseQuery { + uint32 code = 1; + // bytes data = 2; // use "value" instead. + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 index = 5; + bytes key = 6; + bytes value = 7; + tendermint.crypto.ProofOps proof_ops = 8; + int64 height = 9; + string codespace = 10; +} + +message ResponseBeginBlock { + repeated Event events = 1 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; +} + +message ResponseCheckTx { + uint32 code = 1; + bytes data = 2; + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 gas_wanted = 5 [json_name = "gas_wanted"]; + int64 gas_used = 6 [json_name = "gas_used"]; + repeated Event events = 7 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; + string codespace = 8; +} + +message ResponseDeliverTx { + uint32 code = 1; + bytes data = 2; + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 gas_wanted = 5 [json_name = "gas_wanted"]; + int64 gas_used = 6 [json_name = "gas_used"]; + repeated Event events = 7 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; + string codespace = 8; +} + +message ResponseEndBlock { + repeated ValidatorUpdate validator_updates = 1 + [(gogoproto.nullable) = false]; + ConsensusParams consensus_param_updates = 2; + repeated Event events = 3 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; +} + +message ResponseCommit { + // reserve 1 + bytes data = 2; + int64 retain_height = 3; +} + +message ResponseListSnapshots { + repeated Snapshot snapshots = 1; +} + +message ResponseOfferSnapshot { + Result result = 1; + + enum Result { + UNKNOWN = 0; // Unknown result, abort all snapshot restoration + ACCEPT = 1; // Snapshot accepted, apply chunks + ABORT = 2; // Abort all snapshot restoration + REJECT = 3; // Reject this specific snapshot, try others + REJECT_FORMAT = 4; // Reject all snapshots of this format, try others + REJECT_SENDER = 5; // Reject all snapshots from the sender(s), try others + } +} + +message ResponseLoadSnapshotChunk { + bytes chunk = 1; +} + +message ResponseApplySnapshotChunk { + Result result = 1; + repeated uint32 refetch_chunks = 2; // Chunks to refetch and reapply + repeated string reject_senders = 3; // Chunk senders to reject and ban + + enum Result { + UNKNOWN = 0; // Unknown result, abort all snapshot restoration + ACCEPT = 1; // Chunk successfully accepted + ABORT = 2; // Abort all snapshot restoration + RETRY = 3; // Retry chunk (combine with refetch and reject) + RETRY_SNAPSHOT = 4; // Retry snapshot (combine with refetch and reject) + REJECT_SNAPSHOT = 5; // Reject this snapshot, try others + } +} + +//---------------------------------------- +// Misc. + +// ConsensusParams contains all consensus-relevant parameters +// that can be adjusted by the abci app +message ConsensusParams { + BlockParams block = 1; + tendermint.types.EvidenceParams evidence = 2; + tendermint.types.ValidatorParams validator = 3; + tendermint.types.VersionParams version = 4; +} + +// BlockParams contains limits on the block size. +message BlockParams { + // Note: must be greater than 0 + int64 max_bytes = 1; + // Note: must be greater or equal to -1 + int64 max_gas = 2; +} + +message LastCommitInfo { + int32 round = 1; + repeated VoteInfo votes = 2 [(gogoproto.nullable) = false]; +} + +// Event allows application developers to attach additional information to +// ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. +// Later, transactions may be queried using these events. +message Event { + string type = 1; + repeated EventAttribute attributes = 2 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "attributes,omitempty" + ]; +} + +// EventAttribute is a single key-value pair, associated with an event. +message EventAttribute { + bytes key = 1; + bytes value = 2; + bool index = 3; // nondeterministic +} + +// TxResult contains results of executing the transaction. +// +// One usage is indexing transaction results. +message TxResult { + int64 height = 1; + uint32 index = 2; + bytes tx = 3; + ResponseDeliverTx result = 4 [(gogoproto.nullable) = false]; +} + +//---------------------------------------- +// Blockchain Types + +// Validator +message Validator { + bytes address = 1; // The first 20 bytes of SHA256(public key) + // PubKey pub_key = 2 [(gogoproto.nullable)=false]; + int64 power = 3; // The voting power +} + +// ValidatorUpdate +message ValidatorUpdate { + tendermint.crypto.PublicKey pub_key = 1 [(gogoproto.nullable) = false]; + int64 power = 2; +} + +// VoteInfo +message VoteInfo { + Validator validator = 1 [(gogoproto.nullable) = false]; + bool signed_last_block = 2; +} + +enum EvidenceType { + UNKNOWN = 0; + DUPLICATE_VOTE = 1; + LIGHT_CLIENT_ATTACK = 2; +} + +message Evidence { + EvidenceType type = 1; + // The offending validator + Validator validator = 2 [(gogoproto.nullable) = false]; + // The height when the offense occurred + int64 height = 3; + // The corresponding time where the offense occurred + google.protobuf.Timestamp time = 4 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true + ]; + // Total voting power of the validator set in case the ABCI application does + // not store historical validators. + // https://github.com/tendermint/tendermint/issues/4581 + int64 total_voting_power = 5; +} + +//---------------------------------------- +// State Sync Types + +message Snapshot { + uint64 height = 1; // The height at which the snapshot was taken + uint32 format = 2; // The application-specific snapshot format + uint32 chunks = 3; // Number of chunks in the snapshot + bytes hash = 4; // Arbitrary snapshot hash, equal only if identical + bytes metadata = 5; // Arbitrary application metadata +} + +//---------------------------------------- +// Service Definition + +service ABCIApplication { + rpc Echo(RequestEcho) returns (ResponseEcho); + rpc Flush(RequestFlush) returns (ResponseFlush); + rpc Info(RequestInfo) returns (ResponseInfo); + rpc SetOption(RequestSetOption) returns (ResponseSetOption); + rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx); + rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx); + rpc Query(RequestQuery) returns (ResponseQuery); + rpc Commit(RequestCommit) returns (ResponseCommit); + rpc InitChain(RequestInitChain) returns (ResponseInitChain); + rpc BeginBlock(RequestBeginBlock) returns (ResponseBeginBlock); + rpc EndBlock(RequestEndBlock) returns (ResponseEndBlock); + rpc ListSnapshots(RequestListSnapshots) returns (ResponseListSnapshots); + rpc OfferSnapshot(RequestOfferSnapshot) returns (ResponseOfferSnapshot); + rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) returns (ResponseLoadSnapshotChunk); + rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk); +} diff --git a/third_party/proto/tendermint/crypto/keys.proto b/third_party/proto/tendermint/crypto/keys.proto new file mode 100644 index 00000000000..16fd7adf3ee --- /dev/null +++ b/third_party/proto/tendermint/crypto/keys.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package tendermint.crypto; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/crypto"; + +import "gogoproto/gogo.proto"; + +// PublicKey defines the keys available for use with Tendermint Validators +message PublicKey { + option (gogoproto.compare) = true; + option (gogoproto.equal) = true; + + oneof sum { + bytes ed25519 = 1; + bytes secp256k1 = 2; + } +} diff --git a/third_party/proto/tendermint/crypto/proof.proto b/third_party/proto/tendermint/crypto/proof.proto new file mode 100644 index 00000000000..975df768539 --- /dev/null +++ b/third_party/proto/tendermint/crypto/proof.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; +package tendermint.crypto; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/crypto"; + +import "gogoproto/gogo.proto"; + +message Proof { + int64 total = 1; + int64 index = 2; + bytes leaf_hash = 3; + repeated bytes aunts = 4; +} + +message ValueOp { + // Encoded in ProofOp.Key. + bytes key = 1; + + // To encode in ProofOp.Data + Proof proof = 2; +} + +message DominoOp { + string key = 1; + string input = 2; + string output = 3; +} + +// ProofOp defines an operation used for calculating Merkle root +// The data could be arbitrary format, providing nessecary data +// for example neighbouring node hash +message ProofOp { + string type = 1; + bytes key = 2; + bytes data = 3; +} + +// ProofOps is Merkle proof defined by the list of ProofOps +message ProofOps { + repeated ProofOp ops = 1 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/tendermint/libs/bits/types.proto b/third_party/proto/tendermint/libs/bits/types.proto new file mode 100644 index 00000000000..3111d113a5b --- /dev/null +++ b/third_party/proto/tendermint/libs/bits/types.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; +package tendermint.libs.bits; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/libs/bits"; + +message BitArray { + int64 bits = 1; + repeated uint64 elems = 2; +} diff --git a/third_party/proto/tendermint/p2p/types.proto b/third_party/proto/tendermint/p2p/types.proto new file mode 100644 index 00000000000..0d42ea40029 --- /dev/null +++ b/third_party/proto/tendermint/p2p/types.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; +package tendermint.p2p; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/p2p"; + +import "gogoproto/gogo.proto"; + +message NetAddress { + string id = 1 [(gogoproto.customname) = "ID"]; + string ip = 2 [(gogoproto.customname) = "IP"]; + uint32 port = 3; +} + +message ProtocolVersion { + uint64 p2p = 1 [(gogoproto.customname) = "P2P"]; + uint64 block = 2; + uint64 app = 3; +} + +message DefaultNodeInfo { + ProtocolVersion protocol_version = 1 [(gogoproto.nullable) = false]; + string default_node_id = 2 [(gogoproto.customname) = "DefaultNodeID"]; + string listen_addr = 3; + string network = 4; + string version = 5; + bytes channels = 6; + string moniker = 7; + DefaultNodeInfoOther other = 8 [(gogoproto.nullable) = false]; +} + +message DefaultNodeInfoOther { + string tx_index = 1; + string rpc_address = 2 [(gogoproto.customname) = "RPCAddress"]; +} diff --git a/third_party/proto/tendermint/types/block.proto b/third_party/proto/tendermint/types/block.proto new file mode 100644 index 00000000000..84e9bb15d86 --- /dev/null +++ b/third_party/proto/tendermint/types/block.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; +package tendermint.types; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; + +import "gogoproto/gogo.proto"; +import "tendermint/types/types.proto"; +import "tendermint/types/evidence.proto"; + +message Block { + Header header = 1 [(gogoproto.nullable) = false]; + Data data = 2 [(gogoproto.nullable) = false]; + tendermint.types.EvidenceList evidence = 3 [(gogoproto.nullable) = false]; + Commit last_commit = 4; +} diff --git a/third_party/proto/tendermint/types/evidence.proto b/third_party/proto/tendermint/types/evidence.proto new file mode 100644 index 00000000000..3b234571ba6 --- /dev/null +++ b/third_party/proto/tendermint/types/evidence.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; +package tendermint.types; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; + +import "gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; +import "tendermint/types/types.proto"; +import "tendermint/types/validator.proto"; + +message Evidence { + oneof sum { + DuplicateVoteEvidence duplicate_vote_evidence = 1; + LightClientAttackEvidence light_client_attack_evidence = 2; + } +} + +// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes. +message DuplicateVoteEvidence { + tendermint.types.Vote vote_a = 1; + tendermint.types.Vote vote_b = 2; + int64 total_voting_power = 3; + int64 validator_power = 4; + google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; +} + +// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client. +message LightClientAttackEvidence { + tendermint.types.LightBlock conflicting_block = 1; + int64 common_height = 2; + repeated tendermint.types.Validator byzantine_validators = 3; + int64 total_voting_power = 4; + google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; +} + +message EvidenceList { + repeated Evidence evidence = 1 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/tendermint/types/params.proto b/third_party/proto/tendermint/types/params.proto new file mode 100644 index 00000000000..0de7d846fbd --- /dev/null +++ b/third_party/proto/tendermint/types/params.proto @@ -0,0 +1,80 @@ +syntax = "proto3"; +package tendermint.types; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; + +import "gogoproto/gogo.proto"; +import "google/protobuf/duration.proto"; + +option (gogoproto.equal_all) = true; + +// ConsensusParams contains consensus critical parameters that determine the +// validity of blocks. +message ConsensusParams { + BlockParams block = 1 [(gogoproto.nullable) = false]; + EvidenceParams evidence = 2 [(gogoproto.nullable) = false]; + ValidatorParams validator = 3 [(gogoproto.nullable) = false]; + VersionParams version = 4 [(gogoproto.nullable) = false]; +} + +// BlockParams contains limits on the block size. +message BlockParams { + // Max block size, in bytes. + // Note: must be greater than 0 + int64 max_bytes = 1; + // Max gas per block. + // Note: must be greater or equal to -1 + int64 max_gas = 2; + // Minimum time increment between consecutive blocks (in milliseconds) If the + // block header timestamp is ahead of the system clock, decrease this value. + // + // Not exposed to the application. + int64 time_iota_ms = 3; +} + +// EvidenceParams determine how we handle evidence of malfeasance. +message EvidenceParams { + // Max age of evidence, in blocks. + // + // The basic formula for calculating this is: MaxAgeDuration / {average block + // time}. + int64 max_age_num_blocks = 1; + + // Max age of evidence, in time. + // + // It should correspond with an app's "unbonding period" or other similar + // mechanism for handling [Nothing-At-Stake + // attacks](https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed). + google.protobuf.Duration max_age_duration = 2 + [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + + // This sets the maximum size of total evidence in bytes that can be committed in a single block. + // and should fall comfortably under the max block bytes. + // Default is 1048576 or 1MB + int64 max_bytes = 3; +} + +// ValidatorParams restrict the public key types validators can use. +// NOTE: uses ABCI pubkey naming, not Amino names. +message ValidatorParams { + option (gogoproto.populate) = true; + option (gogoproto.equal) = true; + + repeated string pub_key_types = 1; +} + +// VersionParams contains the ABCI application version. +message VersionParams { + option (gogoproto.populate) = true; + option (gogoproto.equal) = true; + + uint64 app_version = 1; +} + +// HashedParams is a subset of ConsensusParams. +// +// It is hashed into the Header.ConsensusHash. +message HashedParams { + int64 block_max_bytes = 1; + int64 block_max_gas = 2; +} diff --git a/third_party/proto/tendermint/types/types.proto b/third_party/proto/tendermint/types/types.proto new file mode 100644 index 00000000000..7f7ea74cac2 --- /dev/null +++ b/third_party/proto/tendermint/types/types.proto @@ -0,0 +1,157 @@ +syntax = "proto3"; +package tendermint.types; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; + +import "gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; +import "tendermint/crypto/proof.proto"; +import "tendermint/version/types.proto"; +import "tendermint/types/validator.proto"; + +// BlockIdFlag indicates which BlcokID the signature is for +enum BlockIDFlag { + option (gogoproto.goproto_enum_stringer) = true; + option (gogoproto.goproto_enum_prefix) = false; + + BLOCK_ID_FLAG_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "BlockIDFlagUnknown"]; + BLOCK_ID_FLAG_ABSENT = 1 [(gogoproto.enumvalue_customname) = "BlockIDFlagAbsent"]; + BLOCK_ID_FLAG_COMMIT = 2 [(gogoproto.enumvalue_customname) = "BlockIDFlagCommit"]; + BLOCK_ID_FLAG_NIL = 3 [(gogoproto.enumvalue_customname) = "BlockIDFlagNil"]; +} + +// SignedMsgType is a type of signed message in the consensus. +enum SignedMsgType { + option (gogoproto.goproto_enum_stringer) = true; + option (gogoproto.goproto_enum_prefix) = false; + + SIGNED_MSG_TYPE_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "UnknownType"]; + // Votes + SIGNED_MSG_TYPE_PREVOTE = 1 [(gogoproto.enumvalue_customname) = "PrevoteType"]; + SIGNED_MSG_TYPE_PRECOMMIT = 2 [(gogoproto.enumvalue_customname) = "PrecommitType"]; + + // Proposals + SIGNED_MSG_TYPE_PROPOSAL = 32 [(gogoproto.enumvalue_customname) = "ProposalType"]; +} + +// PartsetHeader +message PartSetHeader { + uint32 total = 1; + bytes hash = 2; +} + +message Part { + uint32 index = 1; + bytes bytes = 2; + tendermint.crypto.Proof proof = 3 [(gogoproto.nullable) = false]; +} + +// BlockID +message BlockID { + bytes hash = 1; + PartSetHeader part_set_header = 2 [(gogoproto.nullable) = false]; +} + +// -------------------------------- + +// Header defines the structure of a Tendermint block header. +message Header { + // basic block info + tendermint.version.Consensus version = 1 [(gogoproto.nullable) = false]; + string chain_id = 2 [(gogoproto.customname) = "ChainID"]; + int64 height = 3; + google.protobuf.Timestamp time = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + + // prev block info + BlockID last_block_id = 5 [(gogoproto.nullable) = false]; + + // hashes of block data + bytes last_commit_hash = 6; // commit from validators from the last block + bytes data_hash = 7; // transactions + + // hashes from the app output from the prev block + bytes validators_hash = 8; // validators for the current block + bytes next_validators_hash = 9; // validators for the next block + bytes consensus_hash = 10; // consensus params for current block + bytes app_hash = 11; // state after txs from the previous block + bytes last_results_hash = 12; // root hash of all results from the txs from the previous block + + // consensus info + bytes evidence_hash = 13; // evidence included in the block + bytes proposer_address = 14; // original proposer of the block +} + +// Data contains the set of transactions included in the block +message Data { + // Txs that will be applied by state @ block.Height+1. + // NOTE: not all txs here are valid. We're just agreeing on the order first. + // This means that block.AppHash does not include these txs. + repeated bytes txs = 1; +} + +// Vote represents a prevote, precommit, or commit vote from validators for +// consensus. +message Vote { + SignedMsgType type = 1; + int64 height = 2; + int32 round = 3; + BlockID block_id = 4 + [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"]; // zero if vote is nil. + google.protobuf.Timestamp timestamp = 5 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes validator_address = 6; + int32 validator_index = 7; + bytes signature = 8; +} + +// Commit contains the evidence that a block was committed by a set of validators. +message Commit { + int64 height = 1; + int32 round = 2; + BlockID block_id = 3 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"]; + repeated CommitSig signatures = 4 [(gogoproto.nullable) = false]; +} + +// CommitSig is a part of the Vote included in a Commit. +message CommitSig { + BlockIDFlag block_id_flag = 1; + bytes validator_address = 2; + google.protobuf.Timestamp timestamp = 3 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes signature = 4; +} + +message Proposal { + SignedMsgType type = 1; + int64 height = 2; + int32 round = 3; + int32 pol_round = 4; + BlockID block_id = 5 [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false]; + google.protobuf.Timestamp timestamp = 6 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes signature = 7; +} + +message SignedHeader { + Header header = 1; + Commit commit = 2; +} + +message LightBlock { + SignedHeader signed_header = 1; + tendermint.types.ValidatorSet validator_set = 2; +} + +message BlockMeta { + BlockID block_id = 1 [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false]; + int64 block_size = 2; + Header header = 3 [(gogoproto.nullable) = false]; + int64 num_txs = 4; +} + +// TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. +message TxProof { + bytes root_hash = 1; + bytes data = 2; + tendermint.crypto.Proof proof = 3; +} diff --git a/third_party/proto/tendermint/types/validator.proto b/third_party/proto/tendermint/types/validator.proto new file mode 100644 index 00000000000..49860b96d6b --- /dev/null +++ b/third_party/proto/tendermint/types/validator.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; +package tendermint.types; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; + +import "gogoproto/gogo.proto"; +import "tendermint/crypto/keys.proto"; + +message ValidatorSet { + repeated Validator validators = 1; + Validator proposer = 2; + int64 total_voting_power = 3; +} + +message Validator { + bytes address = 1; + tendermint.crypto.PublicKey pub_key = 2 [(gogoproto.nullable) = false]; + int64 voting_power = 3; + int64 proposer_priority = 4; +} + +message SimpleValidator { + tendermint.crypto.PublicKey pub_key = 1; + int64 voting_power = 2; +} diff --git a/third_party/proto/tendermint/version/types.proto b/third_party/proto/tendermint/version/types.proto new file mode 100644 index 00000000000..6061868bd43 --- /dev/null +++ b/third_party/proto/tendermint/version/types.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; +package tendermint.version; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/version"; + +import "gogoproto/gogo.proto"; + +// App includes the protocol and software version for the application. +// This information is included in ResponseInfo. The App.Protocol can be +// updated in ResponseEndBlock. +message App { + uint64 protocol = 1; + string software = 2; +} + +// Consensus captures the consensus rules for processing a block in the blockchain, +// including all blockchain data structures and the rules of the application's +// state transition machine. +message Consensus { + option (gogoproto.equal) = true; + + uint64 block = 1; + uint64 app = 2; +} diff --git a/x/liquidity/abci.go b/x/liquidity/abci.go new file mode 100644 index 00000000000..9f3ba2e5a99 --- /dev/null +++ b/x/liquidity/abci.go @@ -0,0 +1,25 @@ +package liquidity + +import ( + "time" + + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// In the Begin blocker of the liquidity module, +// Reinitialize batch messages that were not executed in the previous batch and delete batch messages that were executed or ready to delete. +func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { + defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) + k.DeleteAndInitPoolBatches(ctx) +} + +// In case of deposit, withdraw, and swap msgs, unlike other normal tx msgs, +// collect them in the liquidity pool batch and perform an execution once at the endblock to calculate and use the universal price. +func EndBlocker(ctx sdk.Context, k keeper.Keeper) { + defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker) + k.ExecutePoolBatches(ctx) +} diff --git a/x/liquidity/client/cli/cli_test.go b/x/liquidity/client/cli/cli_test.go new file mode 100644 index 00000000000..2bf56bec506 --- /dev/null +++ b/x/liquidity/client/cli/cli_test.go @@ -0,0 +1,1597 @@ +//go:build norace +// +build norace + +package cli_test + +import ( + "context" + "encoding/json" + "fmt" + "io" + "strings" + "testing" + "time" + + "github.com/gogo/protobuf/proto" + "github.com/spf13/viper" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/testutil" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils" + + lapp "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/client/cli" + liquiditytestutil "github.com/cosmos/gaia/v9/x/liquidity/client/testutil" + liquiditytypes "github.com/cosmos/gaia/v9/x/liquidity/types" + + tmcli "github.com/tendermint/tendermint/libs/cli" + tmjson "github.com/tendermint/tendermint/libs/json" + tmlog "github.com/tendermint/tendermint/libs/log" + tmtypes "github.com/tendermint/tendermint/types" + tmdb "github.com/tendermint/tm-db" +) + +type IntegrationTestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network + + db *tmdb.MemDB // in-memory database is needed for exporting genesis cli integration test +} + +// SetupTest creates a new network for _each_ integration test. We create a new +// network for each test because there are some state modifications that are +// needed to be made in order to make useful queries. However, we don't want +// these state changes to be present in other tests. +func (s *IntegrationTestSuite) SetupTest() { + s.T().Log("setting up integration test suite") + + db := tmdb.NewMemDB() + + cfg := liquiditytestutil.NewConfig(db) + cfg.NumValidators = 1 + + var liquidityGenState liquiditytypes.GenesisState + err := cfg.Codec.UnmarshalJSON(cfg.GenesisState[liquiditytypes.ModuleName], &liquidityGenState) + s.Require().NoError(err) + + liquidityGenState.Params = liquiditytypes.DefaultParams() + + cfg.GenesisState[liquiditytypes.ModuleName] = cfg.Codec.MustMarshalJSON(&liquidityGenState) + cfg.AccountTokens = sdk.NewInt(100_000_000_000) // node0token denom + cfg.StakingTokens = sdk.NewInt(100_000_000_000) // stake denom + + genesisStateGov := govtypes.DefaultGenesisState() + genesisStateGov.DepositParams = govtypes.NewDepositParams(sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, govtypes.DefaultMinDepositTokens)), time.Duration(15)*time.Second) + genesisStateGov.VotingParams = govtypes.NewVotingParams(time.Duration(3) * time.Second) + genesisStateGov.TallyParams.Quorum = sdk.MustNewDecFromStr("0.01") + bz, err := cfg.Codec.MarshalJSON(genesisStateGov) + s.Require().NoError(err) + cfg.GenesisState["gov"] = bz + + s.cfg = cfg + s.network = network.New(s.T(), s.cfg) + s.db = db + + _, err = s.network.WaitForHeight(1) + s.Require().NoError(err) +} + +// TearDownTest cleans up the curret test network after each test in the suite. +func (s *IntegrationTestSuite) TearDownTest() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +// TestIntegrationTestSuite every integration test suite. +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} + +func (s *IntegrationTestSuite) TestNewCreatePoolCmd() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + testCases := []struct { + name string + args []string + expectErr bool + respType proto.Message + expectedCode uint32 + }{ + { + "invalid pool type id", + []string{ + "invalidpooltypeid", + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + true, nil, 0, + }, + { + "pool type id is not supported", + []string{ + fmt.Sprintf("%d", uint32(2)), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000)), sdk.NewCoin("denomZ", sdk.NewInt(100_000_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + true, nil, 0, + }, + { + "invalid number of denoms", + []string{ + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000)), sdk.NewCoin("denomZ", sdk.NewInt(100_000_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + true, nil, 0, + }, + { + "deposit coin less than minimum deposit amount", + []string{ + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(1_000)), sdk.NewCoin(denomY, sdk.NewInt(10_000_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, &sdk.TxResponse{}, 9, + }, + { + "valid transaction", + []string{ + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, &sdk.TxResponse{}, 0, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.NewCreatePoolCmd() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestNewDepositWithinBatchCmd() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + respType proto.Message + expectedCode uint32 + }{ + { + "invalid pool id", + []string{ + "invalidpoolid", + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(1_000_000)), sdk.NewCoin(denomY, sdk.NewInt(1_000_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + true, nil, 0, + }, + { + "invalid number of denoms", + []string{ + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(1_000_000)), sdk.NewCoin(denomY, sdk.NewInt(1_000_000)), sdk.NewCoin("denomZ", sdk.NewInt(1_000_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + true, nil, 0, + }, + { + "valid transaction", + []string{ + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(10_000_000)), sdk.NewCoin(denomY, sdk.NewInt(10_000_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, &sdk.TxResponse{}, 0, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.NewDepositWithinBatchCmd() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestNewWithdrawWithinBatchCmd() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + respType proto.Message + expectedCode uint32 + }{ + { + "invalid pool id", + []string{ + "invalidpoolid", + sdk.NewCoins(sdk.NewCoin("poolC33A77E752C183913636A37FE1388ACA22FE7BED792BEB2E72EF2DA857703D8D", sdk.NewInt(10_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + true, nil, 0, + }, + { + "bad pool coin", + []string{ + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin("badpoolcoindenom", sdk.NewInt(10_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, &sdk.TxResponse{}, 29, + }, + { + "valid transaction", + []string{ + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin("poolC33A77E752C183913636A37FE1388ACA22FE7BED792BEB2E72EF2DA857703D8D", sdk.NewInt(10_000))).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, &sdk.TxResponse{}, 0, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.NewWithdrawWithinBatchCmd() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestNewSwapWithinBatchCmd() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + respType proto.Message + expectedCode uint32 + }{ + { + "invalid pool id", + []string{ + "invalidpoolid", + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(10_000))).String(), + denomY, + fmt.Sprintf("%.2f", 0.02), + fmt.Sprintf("%.3f", 0.003), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + true, nil, 0, + }, + { + "swap type id not supported", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", uint32(2)), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(10_000))).String(), + denomY, + fmt.Sprintf("%.2f", 0.02), + fmt.Sprintf("%.2f", 0.03), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + true, nil, 0, + }, + { + "bad offer coin fee", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(10_000))).String(), + denomY, + fmt.Sprintf("%.2f", 0.02), + fmt.Sprintf("%.2f", 0.01), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, &sdk.TxResponse{}, 35, + }, + { + "valid transaction", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", liquiditytypes.DefaultSwapTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(10_000))).String(), + denomY, + fmt.Sprintf("%.2f", 1.0), + fmt.Sprintf("%.3f", 0.003), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, &sdk.TxResponse{}, 0, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.NewSwapWithinBatchCmd() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetCmdQueryParams() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectedOutput string + }{ + { + "json output", + []string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, + `{"pool_types":[{"id":1,"name":"StandardLiquidityPool","min_reserve_coin_num":2,"max_reserve_coin_num":2,"description":"Standard liquidity pool with pool price function X/Y, ESPM constraint, and two kinds of reserve coins"}],"min_init_deposit_amount":"1000000","init_pool_coin_mint_amount":"1000000","max_reserve_coin_amount":"0","pool_creation_fee":[{"denom":"stake","amount":"40000000"}],"swap_fee_rate":"0.003000000000000000","withdraw_fee_rate":"0.000000000000000000","max_order_amount_ratio":"0.100000000000000000","unit_batch_height":1,"circuit_breaker_enabled":false}`, + }, + { + "text output", + []string{fmt.Sprintf("--%s=text", tmcli.OutputFlag)}, + `circuit_breaker_enabled: false +init_pool_coin_mint_amount: "1000000" +max_order_amount_ratio: "0.100000000000000000" +max_reserve_coin_amount: "0" +min_init_deposit_amount: "1000000" +pool_creation_fee: +- amount: "40000000" + denom: stake +pool_types: +- description: Standard liquidity pool with pool price function X/Y, ESPM constraint, + and two kinds of reserve coins + id: 1 + max_reserve_coin_num: 2 + min_reserve_coin_num: 2 + name: StandardLiquidityPool +swap_fee_rate: "0.003000000000000000" +unit_batch_height: 1 +withdraw_fee_rate: "0.000000000000000000"`, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryParams() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + s.Require().NoError(err) + s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String())) + }) + } +} + +func (s *IntegrationTestSuite) TestGetCmdQueryLiquidityPool() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "with invalid pool id", + []string{ + "invalidpoolid", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with not supported pool id", + []string{ + fmt.Sprintf("%d", uint32(2)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case with pool id", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + { + "with invalid pool coin denom", + []string{ + fmt.Sprintf("--%s=%s", cli.FlagPoolCoinDenom, "invalid_value"), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with empty pool coin denom", + []string{ + fmt.Sprintf("--%s", cli.FlagPoolCoinDenom), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case with pool coin denom", + []string{ + fmt.Sprintf("--%s=%s", cli.FlagPoolCoinDenom, "poolC33A77E752C183913636A37FE1388ACA22FE7BED792BEB2E72EF2DA857703D8D"), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + { + "with invalid reserve acc", + []string{ + fmt.Sprintf("--%s=%s", cli.FlagReserveAcc, "invalid_value"), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with empty reserve acc", + []string{ + fmt.Sprintf("--%s", cli.FlagReserveAcc), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case with reserve acc", + []string{ + fmt.Sprintf("--%s=%s", cli.FlagReserveAcc, "cosmos1cva80e6jcxpezd3k5dl7zwy2eg30u7ld3y0a67"), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryLiquidityPool() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var resp liquiditytypes.QueryLiquidityPoolResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp) + s.Require().NoError(err) + s.Require().Equal(uint64(1), resp.GetPool().Id) + s.Require().Equal(uint32(1), resp.GetPool().TypeId) + s.Require().Len(resp.GetPool().ReserveCoinDenoms, 2) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetCmdQueryLiquidityPools() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "valid case", + []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryLiquidityPools() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var resps liquiditytypes.QueryLiquidityPoolsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resps) + s.Require().NoError(err) + + for _, pool := range resps.GetPools() { + s.Require().Equal(uint64(1), pool.Id) + s.Require().Equal(uint32(1), pool.TypeId) + s.Require().Len(pool.ReserveCoinDenoms, 2) + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetCmdQueryLiquidityPoolBatch() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "with invalid pool id", + []string{ + "invalidpoolid", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with not supported pool id", + []string{ + fmt.Sprintf("%d", uint32(2)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryLiquidityPoolBatch() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var resp liquiditytypes.QueryLiquidityPoolBatchResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp) + s.Require().NoError(err) + s.Require().Equal(uint64(1), resp.GetBatch().PoolId) + s.Require().Equal(false, resp.GetBatch().Executed) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetCmdQueryPoolBatchDepositMsg() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + // create new deposit + _, err = liquiditytestutil.MsgDepositWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(10_000_000)), sdk.NewCoin(denomY, sdk.NewInt(10_000_000))).String(), + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "with invalid pool id", + []string{ + "invalidpoolid", + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with not supported pool id", + []string{ + fmt.Sprintf("%d", uint32(2)), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryPoolBatchDepositMsg() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var resp liquiditytypes.QueryPoolBatchDepositMsgResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp) + s.Require().NoError(err) + s.Require().Equal(val.Address.String(), resp.GetDeposit().Msg.DepositorAddress) + s.Require().Equal(true, resp.GetDeposit().Executed) + s.Require().Equal(true, resp.GetDeposit().Succeeded) + s.Require().Equal(true, resp.GetDeposit().ToBeDeleted) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetCmdQueryPoolBatchDepositMsgs() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + // create new deposit + _, err = liquiditytestutil.MsgDepositWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(10_000_000)), sdk.NewCoin(denomY, sdk.NewInt(10_000_000))).String(), + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "with invalid pool id", + []string{ + "invalidpoolid", + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with not supported pool id", + []string{ + fmt.Sprintf("%d", uint32(2)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryPoolBatchDepositMsgs() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var resps liquiditytypes.QueryPoolBatchDepositMsgsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resps) + s.Require().NoError(err) + + for _, deposit := range resps.GetDeposits() { + s.Require().Equal(true, deposit.Executed) + s.Require().Equal(true, deposit.Succeeded) + s.Require().Equal(true, deposit.ToBeDeleted) + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetCmdQueryPoolBatchWithdrawMsg() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + // withdraw pool coin from the pool + poolCoinDenom := "poolC33A77E752C183913636A37FE1388ACA22FE7BED792BEB2E72EF2DA857703D8D" + _, err = liquiditytestutil.MsgWithdrawWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin(poolCoinDenom, sdk.NewInt(10_000))).String(), + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "with invalid pool id", + []string{ + "invalidpoolid", + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with not suppoorted pool id", + []string{ + fmt.Sprintf("%d", uint32(2)), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryPoolBatchWithdrawMsg() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var resp liquiditytypes.QueryPoolBatchWithdrawMsgResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp) + s.Require().NoError(err) + s.Require().Equal(val.Address.String(), resp.GetWithdraw().Msg.WithdrawerAddress) + s.Require().Equal(poolCoinDenom, resp.GetWithdraw().Msg.PoolCoin.Denom) + s.Require().Equal(true, resp.GetWithdraw().Executed) + s.Require().Equal(true, resp.GetWithdraw().Succeeded) + s.Require().Equal(true, resp.GetWithdraw().ToBeDeleted) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetCmdQueryPoolBatchWithdrawMsgs() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(100_000_000)), sdk.NewCoin(denomY, sdk.NewInt(100_000_000))).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + // withdraw pool coin from the pool + _, err = liquiditytestutil.MsgWithdrawWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin("poolC33A77E752C183913636A37FE1388ACA22FE7BED792BEB2E72EF2DA857703D8D", sdk.NewInt(10_000))).String(), + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "with invalid pool id", + []string{ + "invalidpoolid", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with not supported pool id", + []string{ + fmt.Sprintf("%d", uint32(2)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryPoolBatchWithdrawMsgs() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var resps liquiditytypes.QueryPoolBatchWithdrawMsgsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resps) + s.Require().NoError(err) + + for _, withdraw := range resps.GetWithdraws() { + s.Require().Equal(val.Address.String(), withdraw.Msg.WithdrawerAddress) + s.Require().Equal(true, withdraw.Executed) + s.Require().Equal(true, withdraw.Succeeded) + s.Require().Equal(true, withdraw.ToBeDeleted) + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetCmdQueryPoolBatchSwapMsg() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + X := sdk.NewCoin(denomX, sdk.NewInt(1_000_000_000)) + Y := sdk.NewCoin(denomY, sdk.NewInt(5_000_000_000)) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(X, Y).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + // swap coins from the pool + offerCoin := sdk.NewCoin(denomY, sdk.NewInt(50_000_000)) + _, err = liquiditytestutil.MsgSwapWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", liquiditytypes.DefaultSwapTypeID), + offerCoin.String(), + denomX, + fmt.Sprintf("%.3f", 0.019), + fmt.Sprintf("%.3f", 0.003), + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "with invalid pool id", + []string{ + "invalidpoolid", + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with not supported pool id", + []string{ + fmt.Sprintf("%d", uint32(2)), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryPoolBatchSwapMsg() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var resp liquiditytypes.QueryPoolBatchSwapMsgResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp) + s.Require().NoError(err) + s.Require().Equal(val.Address.String(), resp.GetSwap().Msg.SwapRequesterAddress) + s.Require().Equal(true, resp.GetSwap().Executed) + s.Require().Equal(true, resp.GetSwap().Succeeded) + s.Require().Equal(true, resp.GetSwap().ToBeDeleted) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetCircuitBreaker() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + X := sdk.NewCoin(denomX, sdk.NewInt(1_000_000_000)) + Y := sdk.NewCoin(denomY, sdk.NewInt(5_000_000_000)) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(X, Y).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + // swap coins from the pool + offerCoin := sdk.NewCoin(denomY, sdk.NewInt(50_000_000)) + output, err := liquiditytestutil.MsgSwapWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", liquiditytypes.DefaultSwapTypeID), + offerCoin.String(), + denomX, + fmt.Sprintf("%.3f", 0.019), + fmt.Sprintf("%.3f", 0.003), + ) + var txRes sdk.TxResponse + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(output.Bytes(), &txRes)) + s.Require().Equal(txRes.Code, uint32(0)) + s.Require().NoError(err) + + circuitBreakerEnabled := true + circuitBreakerEnabledStr, err := json.Marshal(&circuitBreakerEnabled) + if err != nil { + panic(err) + } + + paramChange := paramscutils.ParamChangeProposalJSON{ + Title: "enable-circuit-breaker", + Description: "enable circuit breaker", + Changes: []paramscutils.ParamChangeJSON{ + { + Subspace: liquiditytypes.ModuleName, + Key: "CircuitBreakerEnabled", + Value: circuitBreakerEnabledStr, + }, + }, + Deposit: sdk.NewCoin(s.cfg.BondDenom, govtypes.DefaultMinDepositTokens).String(), + } + paramChangeProp, err := json.Marshal(¶mChange) + if err != nil { + panic(err) + } + + // create a param change proposal with deposit + _, err = liquiditytestutil.MsgParamChangeProposalExec( + val.ClientCtx, + val.Address.String(), + testutil.WriteToNewTempFile(s.T(), string(paramChangeProp)).Name(), + ) + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + _, err = liquiditytestutil.MsgVote(val.ClientCtx, val.Address.String(), "1", "yes") + s.Require().NoError(err) + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + // check if circuit breaker is enabled + expectedOutput := `{"pool_types":[{"id":1,"name":"StandardLiquidityPool","min_reserve_coin_num":2,"max_reserve_coin_num":2,"description":"Standard liquidity pool with pool price function X/Y, ESPM constraint, and two kinds of reserve coins"}],"min_init_deposit_amount":"1000000","init_pool_coin_mint_amount":"1000000","max_reserve_coin_amount":"0","pool_creation_fee":[{"denom":"stake","amount":"40000000"}],"swap_fee_rate":"0.003000000000000000","withdraw_fee_rate":"0.000000000000000000","max_order_amount_ratio":"0.100000000000000000","unit_batch_height":1,"circuit_breaker_enabled":true}` + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdQueryParams(), []string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)}) + s.Require().NoError(err) + s.Require().Equal(expectedOutput, strings.TrimSpace(out.String())) + + // fail swap coins because of circuit breaker + output, err = liquiditytestutil.MsgSwapWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", liquiditytypes.DefaultSwapTypeID), + offerCoin.String(), + denomX, + fmt.Sprintf("%.3f", 0.019), + fmt.Sprintf("%.3f", 0.003), + ) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(output.Bytes(), &txRes)) + s.Require().Equal(txRes.Code, uint32(40)) + s.Require().Equal(txRes.RawLog, "failed to execute message; message index: 0: circuit breaker is triggered") + + // fail create new pool because of circuit breaker + output, err = liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(X, Y).String(), + ) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(output.Bytes(), &txRes)) + s.Require().Equal(txRes.Code, uint32(40)) + s.Require().Equal(txRes.RawLog, "failed to execute message; message index: 0: circuit breaker is triggered") + + // fail create new deposit because of circuit breaker + _, err = liquiditytestutil.MsgDepositWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(sdk.NewCoin(denomX, sdk.NewInt(10_000_000)), sdk.NewCoin(denomY, sdk.NewInt(10_000_000))).String(), + ) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(output.Bytes(), &txRes)) + s.Require().Equal(txRes.Code, uint32(40)) + s.Require().Equal(txRes.RawLog, "failed to execute message; message index: 0: circuit breaker is triggered") + + // success withdraw pool coin from the pool even though circuit breaker is true + poolCoinDenom := "poolC33A77E752C183913636A37FE1388ACA22FE7BED792BEB2E72EF2DA857703D8D" + output, err = liquiditytestutil.MsgWithdrawWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin(poolCoinDenom, sdk.NewInt(500000))).String(), + ) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(output.Bytes(), &txRes)) + s.Require().Equal(txRes.Code, uint32(0)) + + output, err = liquiditytestutil.MsgWithdrawWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin(poolCoinDenom, sdk.NewInt(499999))).String(), + ) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(output.Bytes(), &txRes)) + s.Require().Equal(txRes.Code, uint32(0)) + + // withdraw last pool coin + output, err = liquiditytestutil.MsgWithdrawWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin(poolCoinDenom, sdk.NewInt(1))).String(), + ) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(output.Bytes(), &txRes)) + s.Require().Equal(txRes.Code, uint32(0)) + + // fail withdraw because of the pool is depleted + output, err = liquiditytestutil.MsgWithdrawWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + sdk.NewCoins(sdk.NewCoin(poolCoinDenom, sdk.NewInt(1))).String(), + ) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(output.Bytes(), &txRes)) + s.Require().Equal(txRes.Code, uint32(39)) + s.Require().Equal(txRes.RawLog, "failed to execute message; message index: 0: the pool is depleted of reserve coin, reinitializing is required by deposit") +} + +func (s *IntegrationTestSuite) TestGetCmdQueryPoolBatchSwapMsgs() { + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + X := sdk.NewCoin(denomX, sdk.NewInt(1_000_000_000)) + Y := sdk.NewCoin(denomY, sdk.NewInt(5_000_000_000)) + + // liquidity pool should be created prior to test this integration test + _, err := liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(X, Y).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + // swap coins from the pool + offerCoin := sdk.NewCoin(denomY, sdk.NewInt(50_000_000)) + _, err = liquiditytestutil.MsgSwapWithinBatchExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("%d", liquiditytypes.DefaultSwapTypeID), + offerCoin.String(), + denomX, + fmt.Sprintf("%.3f", 0.019), + fmt.Sprintf("%.3f", 0.003), + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "with invalid pool id", + []string{ + "invalidpoolid", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "with not supported pool id", + []string{ + fmt.Sprintf("%d", uint32(2)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "valid case", + []string{ + fmt.Sprintf("%d", uint32(1)), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryPoolBatchSwapMsgs() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var resps liquiditytypes.QueryPoolBatchSwapMsgsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resps) + s.Require().NoError(err) + + for _, swap := range resps.GetSwaps() { + s.Require().Equal(val.Address.String(), swap.Msg.SwapRequesterAddress) + s.Require().Equal(true, swap.Executed) + s.Require().Equal(true, swap.Succeeded) + s.Require().Equal(true, swap.ToBeDeleted) + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestInitGenesis() { + testCases := []struct { + name string + flags func(dir string) []string + expectErr bool + err error + }{ + { + name: "default genesis state", + flags: func(dir string) []string { + return []string{ + "liquidity-test", + } + }, + expectErr: false, + err: nil, + }, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + testMbm := module.NewBasicManager(liquidity.AppModuleBasic{}) + + home := s.T().TempDir() + logger := tmlog.NewNopLogger() + cfg, err := genutiltest.CreateDefaultTendermintConfig(home) + s.Require().NoError(err) + + serverCtx := server.NewContext(viper.New(), cfg, logger) + interfaceRegistry := types.NewInterfaceRegistry() + marshaler := codec.NewProtoCodec(interfaceRegistry) + clientCtx := client.Context{}. + WithCodec(marshaler). + WithHomeDir(home) + + ctx := context.Background() + ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) + ctx = context.WithValue(ctx, server.ServerContextKey, serverCtx) + + cmd := genutilcli.InitCmd(testMbm, home) + cmd.SetArgs( + tc.flags(home), + ) + + if tc.expectErr { + err := cmd.ExecuteContext(ctx) + s.Require().EqualError(err, tc.err.Error()) + } else { + s.Require().NoError(cmd.ExecuteContext(ctx)) + } + }) + } +} + +func (s *IntegrationTestSuite) TestExportGenesis() { + clientCtx := s.network.Validators[0].ClientCtx + serverCtx := s.network.Validators[0].Ctx + + home := clientCtx.HomeDir + + // verify genesis file saved in temp directory + genDocFile := clientCtx.HomeDir + "/config/genesis.json" + genDoc, err := tmtypes.GenesisDocFromFile(genDocFile) + s.Require().NoError(err) + s.Require().NotNil(genDoc) + + val := s.network.Validators[0] + + // use two different tokens that are minted to the test account + denomX, denomY := liquiditytypes.AlphabeticalDenomPair("node0token", s.network.Config.BondDenom) + X := sdk.NewCoin(denomX, sdk.NewInt(1_000_000_000)) + Y := sdk.NewCoin(denomY, sdk.NewInt(5_000_000_000)) + + // create liquidity pool + _, err = liquiditytestutil.MsgCreatePoolExec( + val.ClientCtx, + val.Address.String(), + fmt.Sprintf("%d", liquiditytypes.DefaultPoolTypeID), + sdk.NewCoins(X, Y).String(), + ) + s.Require().NoError(err) + + err = s.network.WaitForNextBlock() + s.Require().NoError(err) + + cmd := server.ExportCmd( + func(_ tmlog.Logger, _ tmdb.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string, + appOpts servertypes.AppOptions, + ) (servertypes.ExportedApp, error) { + encCfg := lapp.MakeEncodingConfig() + encCfg.Marshaler = codec.NewProtoCodec(encCfg.InterfaceRegistry) + + // get logger and in-memory database + logger := serverCtx.Logger + db := s.db + + var app *lapp.LiquidityApp + if height != -1 { + app = lapp.NewLiquidityApp(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), encCfg, appOpts) + + if err := app.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + app = lapp.NewLiquidityApp(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), encCfg, appOpts) + } + + return app.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) + }, + home, + ) + + args := []string{fmt.Sprintf("--%s=%s", flags.FlagHome, home)} + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args) + s.Require().NoError(err) + + var exportedGenDoc tmtypes.GenesisDoc + err = tmjson.Unmarshal(out.Bytes(), &exportedGenDoc) + s.Require().NoError(err) + + s.Require().Equal(clientCtx.ChainID, exportedGenDoc.ChainID) +} diff --git a/x/liquidity/client/cli/flags.go b/x/liquidity/client/cli/flags.go new file mode 100644 index 00000000000..c1f4985849b --- /dev/null +++ b/x/liquidity/client/cli/flags.go @@ -0,0 +1,21 @@ +package cli + +// DONTCOVER + +import ( + flag "github.com/spf13/pflag" +) + +const ( + FlagPoolCoinDenom = "pool-coin-denom" + FlagReserveAcc = "reserve-acc" +) + +func flagSetPool() *flag.FlagSet { + fs := flag.NewFlagSet("", flag.ContinueOnError) + + fs.String(FlagPoolCoinDenom, "", "The denomination of the pool coin") + fs.String(FlagReserveAcc, "", "The Bech32 address of the reserve account") + + return fs +} diff --git a/x/liquidity/client/cli/query.go b/x/liquidity/client/cli/query.go new file mode 100644 index 00000000000..5d8c06b5629 --- /dev/null +++ b/x/liquidity/client/cli/query.go @@ -0,0 +1,577 @@ +package cli + +// DONTCOVER +// client is excluded from test coverage in the poc phase milestone 1 and will be included in milestone 2 with completeness + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" + "github.com/spf13/cobra" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd() *cobra.Command { + liquidityQueryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the liquidity module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + liquidityQueryCmd.AddCommand( + GetCmdQueryParams(), + GetCmdQueryLiquidityPool(), + GetCmdQueryLiquidityPools(), + GetCmdQueryLiquidityPoolBatch(), + GetCmdQueryPoolBatchDepositMsgs(), + GetCmdQueryPoolBatchDepositMsg(), + GetCmdQueryPoolBatchWithdrawMsgs(), + GetCmdQueryPoolBatchWithdrawMsg(), + GetCmdQueryPoolBatchSwapMsgs(), + GetCmdQueryPoolBatchSwapMsg(), + ) + + return liquidityQueryCmd +} + +// GetCmdQueryParams implements the params query command. +func GetCmdQueryParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Args: cobra.NoArgs, + Short: "Query the values set as liquidity parameters", + Long: strings.TrimSpace( + fmt.Sprintf(`Query values set as liquidity parameters. + +Example: +$ %s query %s params +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Params( + context.Background(), + &types.QueryParamsRequest{}, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(&res.Params) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func GetCmdQueryLiquidityPool() *cobra.Command { + cmd := &cobra.Command{ + Use: "pool [pool-id]", + Short: "Query details of a liquidity pool", + Long: strings.TrimSpace( + fmt.Sprintf(`Query details of a liquidity pool +Example: +$ %[1]s query %[2]s pool 1 + +Example (with pool coin denom): +$ %[1]s query %[2]s pool --pool-coin-denom=[denom] + +Example (with reserve acc): +$ %[1]s query %[2]s pool --reserve-acc=[address] +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + var res *types.QueryLiquidityPoolResponse + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + foundArg := false + queryClient := types.NewQueryClient(clientCtx) + + poolCoinDenom, _ := cmd.Flags().GetString(FlagPoolCoinDenom) + if poolCoinDenom != "" { + foundArg = true + res, err = queryClient.LiquidityPoolByPoolCoinDenom( + context.Background(), + &types.QueryLiquidityPoolByPoolCoinDenomRequest{PoolCoinDenom: poolCoinDenom}, + ) + if err != nil { + return err + } + } + + reserveAcc, _ := cmd.Flags().GetString(FlagReserveAcc) + if !foundArg && reserveAcc != "" { + foundArg = true + res, err = queryClient.LiquidityPoolByReserveAcc( + context.Background(), + &types.QueryLiquidityPoolByReserveAccRequest{ReserveAcc: reserveAcc}, + ) + if err != nil { + return err + } + } + + if !foundArg && len(args) > 0 { + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer for pool-id", args[0]) + } + + if poolID != 0 { + foundArg = true + res, err = queryClient.LiquidityPool( + context.Background(), + &types.QueryLiquidityPoolRequest{PoolId: poolID}, + ) + if err != nil { + return err + } + } + } + + if !foundArg { + return fmt.Errorf("provide the pool-id argument or --%s or --%s flag", FlagPoolCoinDenom, FlagReserveAcc) + } + + return clientCtx.PrintProto(res) + }, + } + cmd.Flags().AddFlagSet(flagSetPool()) + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func GetCmdQueryLiquidityPools() *cobra.Command { + cmd := &cobra.Command{ + Use: "pools", + Args: cobra.NoArgs, + Short: "Query for all liquidity pools", + Long: strings.TrimSpace( + fmt.Sprintf(`Query details about all liquidity pools on a network. +Example: +$ %s query %s pools +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + res, err := queryClient.LiquidityPools( + context.Background(), + &types.QueryLiquidityPoolsRequest{Pagination: pageReq}, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func GetCmdQueryLiquidityPoolBatch() *cobra.Command { + cmd := &cobra.Command{ + Use: "batch [pool-id]", + Args: cobra.ExactArgs(1), + Short: "Query details of a liquidity pool batch", + Long: strings.TrimSpace( + fmt.Sprintf(`Query details of a liquidity pool batch +Example: +$ %s query %s batch 1 +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint32, input a valid unsigned 32-bit integer pool-id", args[0]) + } + + res, err := queryClient.LiquidityPoolBatch( + context.Background(), + &types.QueryLiquidityPoolBatchRequest{PoolId: poolID}, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +func GetCmdQueryPoolBatchDepositMsgs() *cobra.Command { + cmd := &cobra.Command{ + Use: "deposits [pool-id]", + Args: cobra.ExactArgs(1), + Short: "Query all deposit messages of the liquidity pool batch", + Long: strings.TrimSpace( + fmt.Sprintf(`Query all deposit messages of the liquidity pool batch on the specified pool + +If batch messages are normally processed from the endblock, the resulting state is applied and the messages are removed in the beginning of next block. +To query for past blocks, query the block height using the REST/gRPC API of a node that is not pruned. + +Example: +$ %s query %s deposits 1 +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer pool-id", args[0]) + } + + res, err := queryClient.PoolBatchDepositMsgs( + context.Background(), + &types.QueryPoolBatchDepositMsgsRequest{ + PoolId: poolID, + Pagination: pageReq, + }, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func GetCmdQueryPoolBatchDepositMsg() *cobra.Command { + cmd := &cobra.Command{ + Use: "deposit [pool-id] [msg-index]", + Args: cobra.ExactArgs(2), + Short: "Query the deposit messages on the liquidity pool batch", + Long: strings.TrimSpace( + fmt.Sprintf(`Query the deposit messages on the liquidity pool batch for the specified pool-id and msg-index + +If batch messages are normally processed from the endblock, +the resulting state is applied and the messages are removed from the beginning of the next block. +To query for past blocks, query the block height using the REST/gRPC API of a node that is not pruned. + +Example: +$ %s query %s deposit 1 20 +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer for pool-id", args[0]) + } + + msgIndex, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return fmt.Errorf("msg-index %s not a valid uint, input a valid unsigned 32-bit integer for msg-index", args[1]) + } + + res, err := queryClient.PoolBatchDepositMsg( + context.Background(), + &types.QueryPoolBatchDepositMsgRequest{ + PoolId: poolID, + MsgIndex: msgIndex, + }, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func GetCmdQueryPoolBatchWithdrawMsgs() *cobra.Command { + cmd := &cobra.Command{ + Use: "withdraws [pool-id]", + Args: cobra.ExactArgs(1), + Short: "Query for all withdraw messages on the liquidity pool batch", + Long: strings.TrimSpace( + fmt.Sprintf(`Query all withdraw messages on the liquidity pool batch for the specified pool-id + +If batch messages are normally processed from the endblock, +the resulting state is applied and the messages are removed in the beginning of next block. +To query for past blocks, query the block height using the REST/gRPC API of a node that is not pruned. + +Example: +$ %s query %s withdraws 1 +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer pool-id", args[0]) + } + + result, err := queryClient.PoolBatchWithdrawMsgs(context.Background(), &types.QueryPoolBatchWithdrawMsgsRequest{ + PoolId: poolID, Pagination: pageReq, + }) + if err != nil { + return err + } + return clientCtx.PrintProto(result) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func GetCmdQueryPoolBatchWithdrawMsg() *cobra.Command { + cmd := &cobra.Command{ + Use: "withdraw [pool-id] [msg-index]", + Args: cobra.ExactArgs(2), + Short: "Query the withdraw messages in the liquidity pool batch", + Long: strings.TrimSpace( + fmt.Sprintf(`Query the withdraw messages in the liquidity pool batch for the specified pool-id and msg-index + +if the batch message are normally processed from the endblock, +the resulting state is applied and the messages are removed in the beginning of next block. +To query for past blocks, query the block height using the REST/gRPC API of a node that is not pruned. + +Example: +$ %s query %s withdraw 1 20 +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer pool-id", args[0]) + } + + msgIndex, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return fmt.Errorf("msg-index %s not a valid uint, input a valid unsigned 32-bit integer msg-index", args[1]) + } + + res, err := queryClient.PoolBatchWithdrawMsg( + context.Background(), + &types.QueryPoolBatchWithdrawMsgRequest{ + PoolId: poolID, + MsgIndex: msgIndex, + }, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func GetCmdQueryPoolBatchSwapMsgs() *cobra.Command { + cmd := &cobra.Command{ + Use: "swaps [pool-id]", + Args: cobra.ExactArgs(1), + Short: "Query all swap messages in the liquidity pool batch", + Long: strings.TrimSpace( + fmt.Sprintf(`Query all swap messages in the liquidity pool batch for the specified pool-id + +If batch messages are normally processed from the endblock, +the resulting state is applied and the messages are removed in the beginning of next block. +To query for past blocks, query the block height using the REST/gRPC API of a node that is not pruned. + +Example: +$ %s query %s swaps 1 +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer pool-id", args[0]) + } + + res, err := queryClient.PoolBatchSwapMsgs( + context.Background(), + &types.QueryPoolBatchSwapMsgsRequest{ + PoolId: poolID, + Pagination: pageReq, + }, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func GetCmdQueryPoolBatchSwapMsg() *cobra.Command { + cmd := &cobra.Command{ + Use: "swap [pool-id] [msg-index]", + Args: cobra.ExactArgs(2), + Short: "Query for the swap message on the batch of the liquidity pool specified pool-id and msg-index", + Long: strings.TrimSpace( + fmt.Sprintf(`Query for the swap message on the batch of the liquidity pool specified pool-id and msg-index + +If the batch message are normally processed and from the endblock, +the resulting state is applied and the messages are removed in the beginning of next block. +To query for past blocks, query the block height using the REST/gRPC API of a node that is not pruned. + +Example: +$ %s query %s swap 1 20 +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer for pool-id", args[0]) + } + + msgIndex, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return fmt.Errorf("msg-index %s not a valid uint, input a valid unsigned 32-bit integer for msg-index", args[1]) + } + + res, err := queryClient.PoolBatchSwapMsg( + context.Background(), + &types.QueryPoolBatchSwapMsgRequest{ + PoolId: poolID, + MsgIndex: msgIndex, + }, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/liquidity/client/cli/tx.go b/x/liquidity/client/cli/tx.go new file mode 100644 index 00000000000..9bdf4173e3e --- /dev/null +++ b/x/liquidity/client/cli/tx.go @@ -0,0 +1,336 @@ +package cli + +// DONTCOVER +// client is excluded from test coverage in the poc phase milestone 1 and will be included in milestone 2 with completeness + +import ( + "fmt" + "strconv" + "strings" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + "github.com/spf13/cobra" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// GetTxCmd returns a root CLI command handler for all x/liquidity transaction commands. +func GetTxCmd() *cobra.Command { + liquidityTxCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Liquidity transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + liquidityTxCmd.AddCommand( + NewCreatePoolCmd(), + NewDepositWithinBatchCmd(), + NewWithdrawWithinBatchCmd(), + NewSwapWithinBatchCmd(), + ) + + return liquidityTxCmd +} + +// Create new liquidity pool with the specified pool type and deposit coins. +func NewCreatePoolCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "create-pool [pool-type] [deposit-coins]", + Args: cobra.ExactArgs(2), + Short: "Create liquidity pool and deposit coins", + Long: strings.TrimSpace( + fmt.Sprintf(`Create liquidity pool and deposit coins. + +Example: +$ %s tx %s create-pool 1 1000000000uatom,50000000000uusd --from mykey + +This example creates a liquidity pool of pool-type 1 (two coins) and deposits 1000000000uatom and 50000000000uusd. +New liquidity pools can be created only for coin combinations that do not already exist in the network. + +[pool-type]: The id of the liquidity pool-type. The only supported pool type is 1 +[deposit-coins]: The amount of coins to deposit to the liquidity pool. The number of deposit coins must be 2 in pool type 1. +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + poolCreator := clientCtx.GetFromAddress() + + // Get pool type index + poolTypeID, err := strconv.ParseUint(args[0], 10, 32) + if err != nil { + return fmt.Errorf("pool-type %s not a valid uint, input a valid unsigned 32-bit integer for pool-type", args[0]) + } + + // Get deposit coins + depositCoins, err := sdk.ParseCoinsNormalized(args[1]) + if err != nil { + return err + } + + err = depositCoins.Validate() + if err != nil { + return err + } + + if poolTypeID != 1 { + return types.ErrPoolTypeNotExists + } + + if depositCoins.Len() != 2 { + return fmt.Errorf("the number of deposit coins must be two in pool-type 1") + } + + msg := types.NewMsgCreatePool(poolCreator, uint32(poolTypeID), depositCoins) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// Deposit coins to the specified liquidity pool. +func NewDepositWithinBatchCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "deposit [pool-id] [deposit-coins]", + Args: cobra.ExactArgs(2), + Short: "Deposit coins to a liquidity pool", + Long: strings.TrimSpace( + fmt.Sprintf(`Deposit coins a liquidity pool. + +This deposit request is not processed immediately since it is accumulated in the liquidity pool batch. +All requests in a batch are treated equally and executed at the same swap price. + +Example: +$ %s tx %s deposit 1 100000000uatom,5000000000uusd --from mykey + +This example request deposits 100000000uatom and 5000000000uusd to pool-id 1. +Deposits must be the same coin denoms as the reserve coins. + +[pool-id]: The pool id of the liquidity pool +[deposit-coins]: The amount of coins to deposit to the liquidity pool +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + depositor := clientCtx.GetFromAddress() + + // Get pool type index + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer for pool-id", args[0]) + } + + // Get deposit coins + depositCoins, err := sdk.ParseCoinsNormalized(args[1]) + if err != nil { + return err + } + + err = depositCoins.Validate() + if err != nil { + return err + } + + if depositCoins.Len() != 2 { + return fmt.Errorf("the number of deposit coins must be two in the pool-type 1") + } + + msg := types.NewMsgDepositWithinBatch(depositor, poolID, depositCoins) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// Withdraw pool coin from the specified liquidity pool. +func NewWithdrawWithinBatchCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "withdraw [pool-id] [pool-coin]", + Args: cobra.ExactArgs(2), + Short: "Withdraw pool coin from the specified liquidity pool", + Long: strings.TrimSpace( + fmt.Sprintf(`Withdraw pool coin from the specified liquidity pool. + +This swap request is not processed immediately since it is accumulated in the liquidity pool batch. +All requests in a batch are treated equally and executed at the same swap price. + +Example: +$ %s tx %s withdraw 1 10000pool96EF6EA6E5AC828ED87E8D07E7AE2A8180570ADD212117B2DA6F0B75D17A6295 --from mykey + +This example request withdraws 10000 pool coin from the specified liquidity pool. +The appropriate pool coin must be requested from the specified pool. + +[pool-id]: The pool id of the liquidity pool +[pool-coin]: The amount of pool coin to withdraw from the liquidity pool +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + withdrawer := clientCtx.GetFromAddress() + + // Get pool type index + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer for pool-id", args[0]) + } + + // Get pool coin of the target pool + poolCoin, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + + err = poolCoin.Validate() + if err != nil { + return err + } + + msg := types.NewMsgWithdrawWithinBatch(withdrawer, poolID, poolCoin) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// Swap offer coin with demand coin from the specified liquidity pool with the given order price. +func NewSwapWithinBatchCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "swap [pool-id] [swap-type] [offer-coin] [demand-coin-denom] [order-price] [swap-fee-rate]", + Args: cobra.ExactArgs(6), + Short: "Swap offer coin with demand coin from the liquidity pool with the given order price", + Long: strings.TrimSpace( + fmt.Sprintf(`Swap offer coin with demand coin from the liquidity pool with the given order price. + +This swap request is not processed immediately since it is accumulated in the liquidity pool batch. +All requests in a batch are treated equally and executed at the same swap price. +The order of swap requests is ignored since the universal swap price is calculated in every batch to prevent front running. + +The requested swap is executed with a swap price that is calculated from the given swap price function of the pool, the other swap requests, and the liquidity pool coin reserve status. +Swap orders are executed only when the execution swap price is equal to or greater than the submitted order price of the swap order. + +Example: +$ %s tx %s swap 1 1 50000000uusd uatom 0.019 0.003 --from mykey + +For this example, imagine that an existing liquidity pool has with 1000000000uatom and 50000000000uusd. +This example request swaps 50000000uusd for at least 950000uatom with the order price of 0.019 and swap fee rate of 0.003. +A sufficient balance of half of the swap-fee-rate of the offer coin is required to reserve the offer coin fee. + +The order price is the exchange ratio of X/Y, where X is the amount of the first coin and Y is the amount of the second coin when their denoms are sorted alphabetically. +Increasing order price reduces the possibility for your request to be processed and results in buying uatom at a lower price than the pool price. + +For explicit calculations, The swap fee rate must be the value that set as liquidity parameter in the current network. +The only supported swap-type is 1. For the detailed swap algorithm, see https://github.com/cosmos/gaia/v9 + +[pool-id]: The pool id of the liquidity pool +[swap-type]: The swap type of the swap message. The only supported swap type is 1 (instant swap). +[offer-coin]: The amount of offer coin to swap +[demand-coin-denom]: The denomination of the coin to exchange with offer coin +[order-price]: The limit order price for the swap order. The price is the exchange ratio of X/Y where X is the amount of the first coin and Y is the amount of the second coin when their denoms are sorted alphabetically +[swap-fee-rate]: The swap fee rate to pay for swap that is proportional to swap amount. The swap fee rate must be the value that set as liquidity parameter in the current network. +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + swapRequester := clientCtx.GetFromAddress() + + // Get pool id + poolID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer for pool-id", args[0]) + } + + // Get swap type + swapTypeID, err := strconv.ParseUint(args[1], 10, 32) + if err != nil { + return fmt.Errorf("swap-type %s not a valid uint, input a valid unsigned 32-bit integer for swap-type", args[2]) + } + + if swapTypeID != 1 { + return types.ErrSwapTypeNotExists + } + + // Get offer coin + offerCoin, err := sdk.ParseCoinNormalized(args[2]) + if err != nil { + return err + } + + err = offerCoin.Validate() + if err != nil { + return err + } + + err = sdk.ValidateDenom(args[3]) + if err != nil { + return err + } + + orderPrice, err := sdk.NewDecFromStr(args[4]) + if err != nil { + return err + } + + swapFeeRate, err := sdk.NewDecFromStr(args[5]) + if err != nil { + return err + } + + msg := types.NewMsgSwapWithinBatch(swapRequester, poolID, uint32(swapTypeID), offerCoin, args[3], orderPrice, swapFeeRate) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/liquidity/client/testutil/cli_helpers.go b/x/liquidity/client/testutil/cli_helpers.go new file mode 100644 index 00000000000..c89cf14f997 --- /dev/null +++ b/x/liquidity/client/testutil/cli_helpers.go @@ -0,0 +1,144 @@ +package testutil + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/simapp/params" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/testutil" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli" + paramscli "github.com/cosmos/cosmos-sdk/x/params/client/cli" + + liquidityapp "github.com/cosmos/gaia/v9/app" + liquiditycli "github.com/cosmos/gaia/v9/x/liquidity/client/cli" + + dbm "github.com/tendermint/tm-db" +) + +// NewConfig returns config that defines the necessary testing requirements +// used to bootstrap and start an in-process local testing network. +func NewConfig(dbm *dbm.MemDB) network.Config { + encCfg := simapp.MakeTestEncodingConfig() + + cfg := network.DefaultConfig() + cfg.AppConstructor = NewAppConstructor(encCfg, dbm) // the ABCI application constructor + cfg.GenesisState = liquidityapp.ModuleBasics.DefaultGenesis(cfg.Codec) // liquidity genesis state to provide + return cfg +} + +// NewAppConstructor returns a new network AppConstructor. +func NewAppConstructor(encodingCfg params.EncodingConfig, db *dbm.MemDB) network.AppConstructor { + return func(val network.Validator) servertypes.Application { + return liquidityapp.NewLiquidityApp( + val.Ctx.Logger, db, nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0, + liquidityapp.MakeEncodingConfig(), + simapp.EmptyAppOptions{}, + baseapp.SetPruning(storetypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), + baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices), + ) + } +} + +var commonArgs = []string{ + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))).String()), +} + +// MsgCreatePoolExec creates a transaction for creating liquidity pool. +func MsgCreatePoolExec(clientCtx client.Context, from, poolID, depositCoins string, + extraArgs ...string, +) (testutil.BufferWriter, error) { + args := append([]string{ + poolID, + depositCoins, + fmt.Sprintf("--%s=%s", flags.FlagFrom, from), + }, commonArgs...) + + args = append(args, commonArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, liquiditycli.NewCreatePoolCmd(), args) +} + +// MsgDepositWithinBatchExec creates a transaction to deposit new amounts to the pool. +func MsgDepositWithinBatchExec(clientCtx client.Context, from, poolID, depositCoins string, + extraArgs ...string, +) (testutil.BufferWriter, error) { + args := append([]string{ + poolID, + depositCoins, + fmt.Sprintf("--%s=%s", flags.FlagFrom, from), + }, commonArgs...) + + args = append(args, commonArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, liquiditycli.NewDepositWithinBatchCmd(), args) +} + +// MsgWithdrawWithinBatchExec creates a transaction to withraw pool coin amount from the pool. +func MsgWithdrawWithinBatchExec(clientCtx client.Context, from, poolID, poolCoin string, + extraArgs ...string, +) (testutil.BufferWriter, error) { + args := append([]string{ + poolID, + poolCoin, + fmt.Sprintf("--%s=%s", flags.FlagFrom, from), + }, commonArgs...) + + args = append(args, commonArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, liquiditycli.NewWithdrawWithinBatchCmd(), args) +} + +// MsgSwapWithinBatchExec creates a transaction to swap coins in the pool. +func MsgSwapWithinBatchExec(clientCtx client.Context, from, poolID, swapTypeID, + offerCoin, demandCoinDenom, orderPrice, swapFeeRate string, extraArgs ...string, +) (testutil.BufferWriter, error) { + args := append([]string{ + poolID, + swapTypeID, + offerCoin, + demandCoinDenom, + orderPrice, + swapFeeRate, + fmt.Sprintf("--%s=%s", flags.FlagFrom, from), + }, commonArgs...) + + args = append(args, commonArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, liquiditycli.NewSwapWithinBatchCmd(), args) +} + +// MsgParamChangeProposalExec creates a transaction for submitting param change proposal +func MsgParamChangeProposalExec(clientCtx client.Context, from string, file string) (testutil.BufferWriter, error) { + args := append([]string{ + file, + fmt.Sprintf("--%s=%s", flags.FlagFrom, from), + }, commonArgs...) + + paramChangeCmd := paramscli.NewSubmitParamChangeProposalTxCmd() + flags.AddTxFlagsToCmd(paramChangeCmd) + + return clitestutil.ExecTestCLICmd(clientCtx, paramChangeCmd, args) +} + +// MsgVote votes for a proposal +func MsgVote(clientCtx client.Context, from, id, vote string, extraArgs ...string) (testutil.BufferWriter, error) { + args := append([]string{ + id, + vote, + fmt.Sprintf("--%s=%s", flags.FlagFrom, from), + }, commonArgs...) + + args = append(args, extraArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, govcli.NewCmdWeightedVote(), args) +} diff --git a/x/liquidity/doc.go b/x/liquidity/doc.go new file mode 100644 index 00000000000..4dfaa1ee523 --- /dev/null +++ b/x/liquidity/doc.go @@ -0,0 +1,16 @@ +/* +Package liquidity implements a Cosmos SDK module,that provides an implementation +of the serves AMM(Automated Market Makers) style decentralized liquidity providing and +coin swap functions. The module enable anyone to create a liquidity pool, deposit or withdraw coins +from the liquidity pool, and request coin swap to the liquidity pool + +Please refer to the specification under /spec and Resources below for further information. + +Resources + - Liquidity Module Spec https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec + - Liquidity Module Lite Paper https://github.com/cosmos/gaia/v9/blob/develop/doc/LiquidityModuleLightPaper_EN.pdf + - Proposal and milestone https://github.com/b-harvest/Liquidity-Module-For-the-Hub + - Swagger HTTP API doc https://app.swaggerhub.com/apis-docs/bharvest/cosmos-sdk_liquidity_module_rest_and_g_rpc_gateway_docs + - Client doc https://github.com/cosmos/gaia/v9/blob/develop/doc/client.md +*/ +package liquidity diff --git a/x/liquidity/genesis.go b/x/liquidity/genesis.go new file mode 100644 index 00000000000..b047ec68225 --- /dev/null +++ b/x/liquidity/genesis.go @@ -0,0 +1,18 @@ +package liquidity + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// InitGenesis new liquidity genesis +func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, data types.GenesisState) { + keeper.InitGenesis(ctx, data) +} + +// ExportGenesis returns a GenesisState for a given context and keeper. +func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState { + return keeper.ExportGenesis(ctx) +} diff --git a/x/liquidity/genesis_test.go b/x/liquidity/genesis_test.go new file mode 100644 index 00000000000..2eaa483d75b --- /dev/null +++ b/x/liquidity/genesis_test.go @@ -0,0 +1,71 @@ +package liquidity_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestGenesisState(t *testing.T) { + cdc := codec.NewLegacyAmino() + types.RegisterLegacyAminoCodec(cdc) + simapp := app.Setup(false) + + ctx := simapp.BaseApp.NewContext(false, tmproto.Header{}) + genesis := types.DefaultGenesisState() + + liquidity.InitGenesis(ctx, simapp.LiquidityKeeper, *genesis) + + defaultGenesisExported := liquidity.ExportGenesis(ctx, simapp.LiquidityKeeper) + + require.Equal(t, genesis, defaultGenesisExported) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair("denomX", "denomY") + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(1000000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + // begin block, init + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, true) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, true) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + price, _ := sdk.NewDecFromStr("1.1") + offerCoins := []sdk.Coin{sdk.NewCoin(denomX, sdk.NewInt(10000))} + orderPrices := []sdk.Dec{price} + orderAddrs := addrs[1:2] + _, _ = app.TestSwapPool(t, simapp, ctx, offerCoins, orderPrices, orderAddrs, poolID, false) + _, _ = app.TestSwapPool(t, simapp, ctx, offerCoins, orderPrices, orderAddrs, poolID, false) + _, _ = app.TestSwapPool(t, simapp, ctx, offerCoins, orderPrices, orderAddrs, poolID, true) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, _ = app.TestSwapPool(t, simapp, ctx, offerCoins, orderPrices, orderAddrs, poolID, true) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + genesisExported := liquidity.ExportGenesis(ctx, simapp.LiquidityKeeper) + bankGenesisExported := simapp.BankKeeper.ExportGenesis(ctx) + + simapp2 := app.Setup(false) + + ctx2 := simapp2.BaseApp.NewContext(false, tmproto.Header{}) + ctx2 = ctx2.WithBlockHeight(1) + + simapp2.BankKeeper.InitGenesis(ctx2, bankGenesisExported) + liquidity.InitGenesis(ctx2, simapp2.LiquidityKeeper, *genesisExported) + simapp2GenesisExported := liquidity.ExportGenesis(ctx2, simapp2.LiquidityKeeper) + require.Equal(t, genesisExported, simapp2GenesisExported) +} diff --git a/x/liquidity/handler.go b/x/liquidity/handler.go new file mode 100644 index 00000000000..a89909c6c82 --- /dev/null +++ b/x/liquidity/handler.go @@ -0,0 +1,36 @@ +package liquidity + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// NewHandler returns a handler for all "liquidity" type messages. +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.MsgCreatePool: + res, err := msgServer.CreatePool(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgDepositWithinBatch: + res, err := msgServer.DepositWithinBatch(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgWithdrawWithinBatch: + res, err := msgServer.WithdrawWithinBatch(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgSwapWithinBatch: + res, err := msgServer.Swap(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) + } + } +} diff --git a/x/liquidity/handler_test.go b/x/liquidity/handler_test.go new file mode 100644 index 00000000000..a63f69f0fb8 --- /dev/null +++ b/x/liquidity/handler_test.go @@ -0,0 +1,297 @@ +package liquidity_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestBadMsg(t *testing.T) { + simapp, ctx := app.CreateTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + handler := liquidity.NewHandler(simapp.LiquidityKeeper) + _, err := handler(ctx, nil) + require.ErrorIs(t, err, sdkerrors.ErrUnknownRequest) + _, err = handler(ctx, banktypes.NewMsgMultiSend(nil, nil)) + require.ErrorIs(t, err, sdkerrors.ErrUnknownRequest) +} + +func TestMsgServerCreatePool(t *testing.T) { + simapp, ctx := app.CreateTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + handler := liquidity.NewHandler(simapp.LiquidityKeeper) + _, err := handler(ctx, msg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + require.Equal(t, 1, len(pools)) + require.Equal(t, uint64(1), pools[0].Id) + require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1) + require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1]) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.ErrorIs(t, err, types.ErrPoolAlreadyExists) +} + +func TestMsgServerExecuteDeposit(t *testing.T) { + simapp, ctx := app.CreateTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 4, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + app.SaveAccount(simapp, ctx, addrs[1], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + depositA = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA) + depositB = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB) + depositBalance = sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + + depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) + + handler := liquidity.NewHandler(simapp.LiquidityKeeper) + _, err = handler(ctx, depositMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + depositorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) + require.Equal(t, poolCoin.Sub(poolCoinBefore), depositorBalance.Amount) +} + +func TestMsgServerExecuteWithdrawal(t *testing.T) { + simapp, ctx := app.CreateTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + fmt.Println(poolCoinBefore, withdrawerPoolCoinBefore.Amount) + require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) + withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) + + handler := liquidity.NewHandler(simapp.LiquidityKeeper) + _, err = handler(ctx, withdrawMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.True(t, true, poolCoinAfter.IsZero()) + require.True(t, true, withdrawerPoolCoinAfter.IsZero()) + withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) + withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]), withdrawerDenomABalance.Amount) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), withdrawerDenomBBalance.Amount) +} + +func TestMsgServerGetLiquidityPoolMetadata(t *testing.T) { + simapp, ctx := app.CreateTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + handler := liquidity.NewHandler(simapp.LiquidityKeeper) + _, err := handler(ctx, msg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + require.Equal(t, 1, len(pools)) + require.Equal(t, uint64(1), pools[0].Id) + require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1) + require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1]) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.ErrorIs(t, err, types.ErrPoolAlreadyExists) + + metaData := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pools[0]) + require.Equal(t, pools[0].Id, metaData.PoolId) + + reserveCoin := simapp.LiquidityKeeper.GetReserveCoins(ctx, pools[0]) + require.Equal(t, reserveCoin, metaData.ReserveCoins) + require.Equal(t, msg.DepositCoins, metaData.ReserveCoins) + + totalSupply := sdk.NewCoin(pools[0].PoolCoinDenom, simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0])) + require.Equal(t, totalSupply, metaData.PoolCoinTotalSupply) + require.Equal(t, creatorBalance, metaData.PoolCoinTotalSupply) +} + +func TestMsgServerSwap(t *testing.T) { + simapp, ctx := app.CreateTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + // init test app and context + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair("denomX", "denomY") + X := params.MinInitDepositAmount + Y := params.MinInitDepositAmount + + // init addresses for the test + addrs := app.AddTestAddrs(simapp, ctx, 20, params.PoolCreationFee) + + // Create pool + // The create pool msg is not run in batch, but is processed immediately. + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + // In case of deposit, withdraw, and swap msg, unlike other normal tx msgs, + // collect them in the batch and perform an execution at once at the endblock. + + // add a deposit to pool and run batch execution on endblock + app.TestDepositPool(t, simapp, ctx, X, Y, addrs[1:2], poolID, true) + + // next block, reinitialize batch and increase batchIndex at beginBlocker, + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // Create swap msg for test purposes and put it in the batch. + price, _ := sdk.NewDecFromStr("1.1") + priceY, _ := sdk.NewDecFromStr("1.2") + xOfferCoins := []sdk.Coin{ + sdk.NewCoin(denomX, sdk.NewInt(10000)), + sdk.NewCoin(denomX, sdk.NewInt(10000)), + sdk.NewCoin(denomX, sdk.NewInt(10000)), + } + yOfferCoins := []sdk.Coin{sdk.NewCoin(denomY, sdk.NewInt(5000))} + xOrderPrices := []sdk.Dec{price, price, price} + yOrderPrices := []sdk.Dec{priceY} + xOrderAddrs := addrs[1:4] + yOrderAddrs := addrs[5:6] + + msg1 := app.GetSwapMsg(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID) + msg4 := app.GetSwapMsg(t, simapp, ctx, yOfferCoins, yOrderPrices, yOrderAddrs, poolID) + + handler := liquidity.NewHandler(simapp.LiquidityKeeper) + _, err := handler(ctx, msg1[0]) + require.NoError(t, err) + _, err = handler(ctx, msg1[1]) + require.NoError(t, err) + _, err = handler(ctx, msg1[2]) + require.NoError(t, err) + _, err = handler(ctx, msg4[0]) + require.NoError(t, err) + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + notProcessedMsgs := simapp.LiquidityKeeper.GetAllNotProcessedPoolBatchSwapMsgStates(ctx, batch) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, batch) + require.Equal(t, 4, len(msgs)) + require.Equal(t, 4, len(notProcessedMsgs)) +} diff --git a/x/liquidity/keeper/batch.go b/x/liquidity/keeper/batch.go new file mode 100644 index 00000000000..3b5a0a031c0 --- /dev/null +++ b/x/liquidity/keeper/batch.go @@ -0,0 +1,289 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// DeleteAndInitPoolBatches resets batch msg states that were previously executed +// and deletes msg states that were marked to be deleted. +func (k Keeper) DeleteAndInitPoolBatches(ctx sdk.Context) { + k.IterateAllPoolBatches(ctx, func(poolBatch types.PoolBatch) bool { + // Re-initialize the executed batch. + if poolBatch.Executed { + // On the other hand, BatchDeposit, BatchWithdraw, is all handled by the endblock if there is no error. + // If there are BatchMsgs left, reset the Executed, Succeeded flag so that it can be executed in the next batch. + depositMsgs := k.GetAllRemainingPoolBatchDepositMsgStates(ctx, poolBatch) + if len(depositMsgs) > 0 { + for _, msg := range depositMsgs { + msg.Executed = false + msg.Succeeded = false + } + k.SetPoolBatchDepositMsgStatesByPointer(ctx, poolBatch.PoolId, depositMsgs) + } + + withdrawMsgs := k.GetAllRemainingPoolBatchWithdrawMsgStates(ctx, poolBatch) + if len(withdrawMsgs) > 0 { + for _, msg := range withdrawMsgs { + msg.Executed = false + msg.Succeeded = false + } + k.SetPoolBatchWithdrawMsgStatesByPointer(ctx, poolBatch.PoolId, withdrawMsgs) + } + + height := ctx.BlockHeight() + + // In the case of remaining swap msg states, those are either fractionally matched + // or has not yet been expired. + swapMsgs := k.GetAllRemainingPoolBatchSwapMsgStates(ctx, poolBatch) + if len(swapMsgs) > 0 { + for _, msg := range swapMsgs { + if height > msg.OrderExpiryHeight { + msg.ToBeDeleted = true + } else { + msg.Executed = false + msg.Succeeded = false + } + } + k.SetPoolBatchSwapMsgStatesByPointer(ctx, poolBatch.PoolId, swapMsgs) + } + + // Delete all batch msg states that are ready to be deleted. + k.DeleteAllReadyPoolBatchDepositMsgStates(ctx, poolBatch) + k.DeleteAllReadyPoolBatchWithdrawMsgStates(ctx, poolBatch) + k.DeleteAllReadyPoolBatchSwapMsgStates(ctx, poolBatch) + + if err := k.InitNextPoolBatch(ctx, poolBatch); err != nil { + panic(err) + } + } + return false + }) +} + +// InitNextPoolBatch re-initializes the batch and increases the batch index. +func (k Keeper) InitNextPoolBatch(ctx sdk.Context, poolBatch types.PoolBatch) error { + if !poolBatch.Executed { + return types.ErrBatchNotExecuted + } + + poolBatch.Index++ + poolBatch.BeginHeight = ctx.BlockHeight() + poolBatch.Executed = false + + k.SetPoolBatch(ctx, poolBatch) + return nil +} + +// ExecutePoolBatches executes the accumulated msgs in the batch. +// The order is (1)swap, (2)deposit, (3)withdraw. +func (k Keeper) ExecutePoolBatches(ctx sdk.Context) { + params := k.GetParams(ctx) + logger := k.Logger(ctx) + + k.IterateAllPoolBatches(ctx, func(poolBatch types.PoolBatch) bool { + if !poolBatch.Executed && ctx.BlockHeight()%int64(params.UnitBatchHeight) == 0 { + executedMsgCount, err := k.SwapExecution(ctx, poolBatch) + if err != nil { + panic(err) + } + + k.IterateAllPoolBatchDepositMsgStates(ctx, poolBatch, func(batchMsg types.DepositMsgState) bool { + if batchMsg.Executed || batchMsg.ToBeDeleted || batchMsg.Succeeded { + return false + } + executedMsgCount++ + if err := k.ExecuteDeposit(ctx, batchMsg, poolBatch); err != nil { + logger.Error("deposit failed", + "poolID", poolBatch.PoolId, + "batchIndex", poolBatch.Index, + "msgIndex", batchMsg.MsgIndex, + "depositor", batchMsg.Msg.GetDepositor(), + "error", err) + if err := k.RefundDeposit(ctx, batchMsg, poolBatch); err != nil { + panic(err) + } + } + return false + }) + + k.IterateAllPoolBatchWithdrawMsgStates(ctx, poolBatch, func(batchMsg types.WithdrawMsgState) bool { + if batchMsg.Executed || batchMsg.ToBeDeleted || batchMsg.Succeeded { + return false + } + executedMsgCount++ + if err := k.ExecuteWithdrawal(ctx, batchMsg, poolBatch); err != nil { + logger.Error("withdraw failed", + "poolID", poolBatch.PoolId, + "batchIndex", poolBatch.Index, + "msgIndex", batchMsg.MsgIndex, + "withdrawer", batchMsg.Msg.GetWithdrawer(), + "error", err) + if err := k.RefundWithdrawal(ctx, batchMsg, poolBatch); err != nil { + panic(err) + } + } + return false + }) + + // Mark the batch as executed when any msgs were executed. + if executedMsgCount > 0 { + poolBatch.Executed = true + k.SetPoolBatch(ctx, poolBatch) + } + } + return false + }) +} + +// HoldEscrow sends coins to the module account for an escrow. +func (k Keeper) HoldEscrow(ctx sdk.Context, depositor sdk.AccAddress, depositCoins sdk.Coins) error { + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, depositor, types.ModuleName, depositCoins); err != nil { + return err + } + return nil +} + +// If batch messages have expired or have not been processed, coins that were deposited with this function are refunded to the escrow. +func (k Keeper) ReleaseEscrow(ctx sdk.Context, withdrawer sdk.AccAddress, withdrawCoins sdk.Coins) error { + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, withdrawer, withdrawCoins); err != nil { + return err + } + return nil +} + +// Generate inputs and outputs to treat escrow refunds atomically. +func (k Keeper) ReleaseEscrowForMultiSend(withdrawer sdk.AccAddress, withdrawCoins sdk.Coins) ( + banktypes.Input, banktypes.Output, error, +) { + var input banktypes.Input + var output banktypes.Output + + input = banktypes.NewInput(k.accountKeeper.GetModuleAddress(types.ModuleName), withdrawCoins) + output = banktypes.NewOutput(withdrawer, withdrawCoins) + + if err := banktypes.ValidateInputsOutputs([]banktypes.Input{input}, []banktypes.Output{output}); err != nil { + return banktypes.Input{}, banktypes.Output{}, err + } + + return input, output, nil +} + +// In order to deal with the batch at the same time, the coins of msgs are deposited in escrow. +func (k Keeper) DepositWithinBatch(ctx sdk.Context, msg *types.MsgDepositWithinBatch) (types.DepositMsgState, error) { + if err := k.ValidateMsgDepositWithinBatch(ctx, *msg); err != nil { + return types.DepositMsgState{}, err + } + + poolBatch, found := k.GetPoolBatch(ctx, msg.PoolId) + if !found { + return types.DepositMsgState{}, types.ErrPoolBatchNotExists + } + + if poolBatch.BeginHeight == 0 { + poolBatch.BeginHeight = ctx.BlockHeight() + } + + msgState := types.DepositMsgState{ + MsgHeight: ctx.BlockHeight(), + MsgIndex: poolBatch.DepositMsgIndex, + Msg: msg, + } + + if err := k.HoldEscrow(ctx, msg.GetDepositor(), msg.DepositCoins); err != nil { + return types.DepositMsgState{}, err + } + + poolBatch.DepositMsgIndex++ + k.SetPoolBatch(ctx, poolBatch) + k.SetPoolBatchDepositMsgState(ctx, poolBatch.PoolId, msgState) + + return msgState, nil +} + +// In order to deal with the batch at the same time, the coins of msgs are deposited in escrow. +func (k Keeper) WithdrawWithinBatch(ctx sdk.Context, msg *types.MsgWithdrawWithinBatch) (types.WithdrawMsgState, error) { + if err := k.ValidateMsgWithdrawWithinBatch(ctx, *msg); err != nil { + return types.WithdrawMsgState{}, err + } + + poolBatch, found := k.GetPoolBatch(ctx, msg.PoolId) + if !found { + return types.WithdrawMsgState{}, types.ErrPoolBatchNotExists + } + + if poolBatch.BeginHeight == 0 { + poolBatch.BeginHeight = ctx.BlockHeight() + } + + batchPoolMsg := types.WithdrawMsgState{ + MsgHeight: ctx.BlockHeight(), + MsgIndex: poolBatch.WithdrawMsgIndex, + Msg: msg, + } + + if err := k.HoldEscrow(ctx, msg.GetWithdrawer(), sdk.NewCoins(msg.PoolCoin)); err != nil { + return types.WithdrawMsgState{}, err + } + + poolBatch.WithdrawMsgIndex++ + k.SetPoolBatch(ctx, poolBatch) + k.SetPoolBatchWithdrawMsgState(ctx, poolBatch.PoolId, batchPoolMsg) + + return batchPoolMsg, nil +} + +// In order to deal with the batch at the same time, the coins of msgs are deposited in escrow. +func (k Keeper) SwapWithinBatch(ctx sdk.Context, msg *types.MsgSwapWithinBatch, orderExpirySpanHeight int64) (*types.SwapMsgState, error) { + pool, found := k.GetPool(ctx, msg.PoolId) + if !found { + return nil, types.ErrPoolNotExists + } + if k.IsDepletedPool(ctx, pool) { + return nil, types.ErrDepletedPool + } + if err := k.ValidateMsgSwapWithinBatch(ctx, *msg, pool); err != nil { + return nil, err + } + poolBatch, found := k.GetPoolBatch(ctx, msg.PoolId) + if !found { + return nil, types.ErrPoolBatchNotExists + } + + if poolBatch.BeginHeight == 0 { + poolBatch.BeginHeight = ctx.BlockHeight() + } + + currentHeight := ctx.BlockHeight() + + if orderExpirySpanHeight == 0 { + params := k.GetParams(ctx) + u := int64(params.UnitBatchHeight) + orderExpirySpanHeight = (u - currentHeight%u) % u + } + + batchPoolMsg := types.SwapMsgState{ + MsgHeight: currentHeight, + MsgIndex: poolBatch.SwapMsgIndex, + Executed: false, + Succeeded: false, + ToBeDeleted: false, + OrderExpiryHeight: currentHeight + orderExpirySpanHeight, + ExchangedOfferCoin: sdk.NewCoin(msg.OfferCoin.Denom, sdk.ZeroInt()), + RemainingOfferCoin: msg.OfferCoin, + ReservedOfferCoinFee: msg.OfferCoinFee, + Msg: msg, + } + + if err := k.HoldEscrow(ctx, msg.GetSwapRequester(), sdk.NewCoins(msg.OfferCoin.Add(msg.OfferCoinFee))); err != nil { + return nil, err + } + + poolBatch.SwapMsgIndex++ + k.SetPoolBatch(ctx, poolBatch) + k.SetPoolBatchSwapMsgState(ctx, poolBatch.PoolId, batchPoolMsg) + + return &batchPoolMsg, nil +} diff --git a/x/liquidity/keeper/batch_test.go b/x/liquidity/keeper/batch_test.go new file mode 100644 index 00000000000..a91f0dd4e4f --- /dev/null +++ b/x/liquidity/keeper/batch_test.go @@ -0,0 +1,1243 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +const ( + DenomX = "denomX" + DenomY = "denomY" + DenomA = "denomA" + DenomB = "denomB" +) + +func TestBadDeposit(t *testing.T) { + simapp, ctx := app.CreateTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + depositCoins := sdk.NewCoins(sdk.NewCoin(DenomX, params.MinInitDepositAmount), sdk.NewCoin(DenomY, params.MinInitDepositAmount)) + depositorAddr := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) + + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, &types.MsgCreatePool{ + PoolCreatorAddress: depositorAddr.String(), + PoolTypeId: types.DefaultPoolTypeID, + DepositCoins: depositCoins, + }) + require.NoError(t, err) + + // deposit with empty message + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, &types.MsgDepositWithinBatch{}) + require.ErrorIs(t, err, types.ErrPoolNotExists) + + // deposit coins more than it has + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, &types.MsgDepositWithinBatch{ + DepositorAddress: depositorAddr.String(), + PoolId: pool.Id, + DepositCoins: sdk.NewCoins(sdk.NewCoin(DenomX, sdk.OneInt()), sdk.NewCoin(DenomY, sdk.OneInt())), + }) + require.ErrorIs(t, err, sdkerrors.ErrInsufficientFunds) + + // forcefully delete current pool batch + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, pool.Id) + require.True(t, found) + simapp.LiquidityKeeper.DeletePoolBatch(ctx, batch) + // deposit coins when there is no pool batch + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, &types.MsgDepositWithinBatch{ + DepositorAddress: depositorAddr.String(), + PoolId: pool.Id, + DepositCoins: sdk.NewCoins(sdk.NewCoin(DenomX, sdk.OneInt()), sdk.NewCoin(DenomY, sdk.OneInt())), + }) + require.ErrorIs(t, err, types.ErrPoolBatchNotExists) +} + +func TestBadWithdraw(t *testing.T) { + simapp, ctx := app.CreateTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + depositCoins := sdk.NewCoins(sdk.NewCoin(DenomX, params.MinInitDepositAmount), sdk.NewCoin(DenomY, params.MinInitDepositAmount)) + depositorAddr := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) + + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, &types.MsgCreatePool{ + PoolCreatorAddress: depositorAddr.String(), + PoolTypeId: types.DefaultPoolTypeID, + DepositCoins: depositCoins, + }) + require.NoError(t, err) + + // withdraw with empty message + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, &types.MsgWithdrawWithinBatch{}) + require.ErrorIs(t, err, types.ErrPoolNotExists) + + balance := simapp.BankKeeper.GetBalance(ctx, depositorAddr, pool.PoolCoinDenom) + + // mint extra pool coins to test if below fails + require.NoError(t, simapp.BankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(pool.PoolCoinDenom, sdk.NewInt(1000))))) + // withdraw pool coins more than it has + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, &types.MsgWithdrawWithinBatch{ + WithdrawerAddress: depositorAddr.String(), + PoolId: pool.Id, + PoolCoin: balance.Add(sdk.NewCoin(pool.PoolCoinDenom, sdk.OneInt())), + }) + require.ErrorIs(t, err, sdkerrors.ErrInsufficientFunds) + + // forcefully delete current pool batch + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, pool.Id) + require.True(t, found) + simapp.LiquidityKeeper.DeletePoolBatch(ctx, batch) + // withdraw pool coins when there is no pool batch + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, &types.MsgWithdrawWithinBatch{ + WithdrawerAddress: depositorAddr.String(), + PoolId: pool.Id, + PoolCoin: sdk.NewCoin(pool.PoolCoinDenom, sdk.OneInt()), + }) + require.ErrorIs(t, err, types.ErrPoolBatchNotExists) +} + +func TestBadSwap(t *testing.T) { + simapp, ctx := app.CreateTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + depositCoins := sdk.NewCoins(sdk.NewCoin(DenomX, params.MinInitDepositAmount), sdk.NewCoin(DenomY, params.MinInitDepositAmount)) + depositorAddr := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) + + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, &types.MsgCreatePool{ + PoolCreatorAddress: depositorAddr.String(), + PoolTypeId: types.DefaultPoolTypeID, + DepositCoins: depositCoins, + }) + require.NoError(t, err) + + // swap with empty message + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, &types.MsgSwapWithinBatch{}, 0) + require.ErrorIs(t, err, types.ErrPoolNotExists) + + orderPrice := sdk.OneDec() + + // swap coin more than it has + offerCoin := sdk.NewCoin(DenomX, sdk.NewInt(100000)) + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, &types.MsgSwapWithinBatch{ + SwapRequesterAddress: depositorAddr.String(), + PoolId: pool.Id, + SwapTypeId: types.DefaultSwapTypeID, + OfferCoin: offerCoin, + DemandCoinDenom: DenomY, + OfferCoinFee: types.GetOfferCoinFee(offerCoin, params.SwapFeeRate), + OrderPrice: orderPrice, + }, 0) + require.ErrorIs(t, err, sdkerrors.ErrInsufficientFunds) + + // when swap fails, user's balance should never change + app.SaveAccount(simapp, ctx, depositorAddr, sdk.NewCoins(offerCoin)) + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, &types.MsgSwapWithinBatch{ + SwapRequesterAddress: depositorAddr.String(), + PoolId: pool.Id, + SwapTypeId: types.DefaultSwapTypeID, + OfferCoin: offerCoin, + DemandCoinDenom: DenomY, + OfferCoinFee: types.GetOfferCoinFee(offerCoin, params.SwapFeeRate), + OrderPrice: orderPrice, + }, 0) + require.ErrorIs(t, err, sdkerrors.ErrInsufficientFunds) + balance := simapp.BankKeeper.GetBalance(ctx, depositorAddr, DenomX) + require.Equal(t, offerCoin, balance) + + // forcefully delete current pool batch + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, pool.Id) + require.True(t, found) + simapp.LiquidityKeeper.DeletePoolBatch(ctx, batch) + // swap coin when there is no pool batch + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, &types.MsgSwapWithinBatch{ + SwapRequesterAddress: depositorAddr.String(), + PoolId: pool.Id, + SwapTypeId: types.DefaultSwapTypeID, + OfferCoin: offerCoin, + DemandCoinDenom: DenomY, + OfferCoinFee: types.GetOfferCoinFee(offerCoin, params.SwapFeeRate), + OrderPrice: orderPrice, + }, 0) + require.ErrorIs(t, err, types.ErrPoolBatchNotExists) +} + +func TestCreateDepositWithdrawWithinBatch(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + denomA, denomB := types.AlphabeticalDenomPair(DenomA, DenomB) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(1000000000) + deposit := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) + + A := sdk.NewInt(1000000000000) + B := sdk.NewInt(1000000000000) + depositAB := sdk.NewCoins(sdk.NewCoin(denomA, A), sdk.NewCoin(denomB, B)) + + // set accounts for creator, depositor, withdrawer, balance for deposit + addrs := app.AddTestAddrs(simapp, ctx, 4, params.PoolCreationFee) + + app.SaveAccount(simapp, ctx, addrs[0], deposit.Add(depositAB...)) // pool creator + depositX := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomX) + depositY := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomY) + depositBalance := sdk.NewCoins(depositX, depositY) + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], DenomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalanceAB := sdk.NewCoins(depositA, depositB) + require.Equal(t, deposit, depositBalance) + require.Equal(t, depositAB, depositBalanceAB) + feePoolAcc := simapp.AccountKeeper.GetModuleAddress(distrtypes.ModuleName) + feePoolBalance := simapp.BankKeeper.GetAllBalances(ctx, feePoolAcc) + + // Success case, create Liquidity pool + poolTypeID := types.DefaultPoolTypeID + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + // Verify PoolCreationFee pay successfully + feePoolBalance = feePoolBalance.Add(params.PoolCreationFee...) + require.Equal(t, params.PoolCreationFee, feePoolBalance) + + // Fail case, reset deposit balance for pool already exists case + app.SaveAccount(simapp, ctx, addrs[0], deposit) + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.ErrorIs(t, err, types.ErrPoolAlreadyExists) + + // reset deposit balance without PoolCreationFee of pool creator + // Fail case, insufficient balances for pool creation fee case + msgAB := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalanceAB) + app.SaveAccount(simapp, ctx, addrs[0], depositAB) + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msgAB) + require.ErrorIs(t, types.ErrInsufficientPoolCreationFee, err) + + // Success case, create another pool + msgAB = types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalanceAB) + app.SaveAccount(simapp, ctx, addrs[0], depositAB.Add(params.PoolCreationFee...)) + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msgAB) + require.NoError(t, err) + + // Verify PoolCreationFee pay successfully + feePoolBalance = simapp.BankKeeper.GetAllBalances(ctx, feePoolAcc) + require.Equal(t, params.PoolCreationFee.Add(params.PoolCreationFee...), feePoolBalance) + + // verify created liquidity pool + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + poolID := pools[0].Id + require.Equal(t, 2, len(pools)) + // require.Equal(t, uint64(1), poolID) + require.Equal(t, denomX, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomY, pools[0].ReserveCoinDenoms[1]) + + // verify minted pool coin + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + // begin block, init + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // set pool depositor account + app.SaveAccount(simapp, ctx, addrs[1], deposit) // pool creator + depositX = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomX) + depositY = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomY) + depositBalance = sdk.NewCoins(depositX, depositY) + require.Equal(t, deposit, depositBalance) + + depositMsg := types.NewMsgDepositWithinBatch(addrs[1], poolID, depositBalance) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + depositorBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + depositorBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + require.Equal(t, sdk.ZeroInt(), depositorBalanceX.Amount) + require.Equal(t, sdk.ZeroInt(), depositorBalanceY.Amount) + require.Equal(t, denomX, depositorBalanceX.Denom) + require.Equal(t, denomY, depositorBalanceY.Denom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + // check escrow balance of module account + moduleAccAddress := simapp.AccountKeeper.GetModuleAddress(types.ModuleName) + moduleAccEscrowAmtX := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, denomX) + moduleAccEscrowAmtY := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, denomY) + require.Equal(t, depositX, moduleAccEscrowAmtX) + require.Equal(t, depositY, moduleAccEscrowAmtY) + + // endblock + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + // verify minted pool coin + poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + depositorPoolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) + require.NotEqual(t, sdk.ZeroInt(), depositBalance) + require.Equal(t, poolCoin, depositorPoolCoinBalance.Amount.Add(creatorBalance.Amount)) + + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, batch) + require.Len(t, msgs, 1) + require.True(t, msgs[0].Executed) + require.True(t, msgs[0].Succeeded) + require.True(t, msgs[0].ToBeDeleted) + require.Equal(t, uint64(1), batch.Index) + + // error balance after endblock + depositorBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + depositorBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + require.Equal(t, sdk.ZeroInt(), depositorBalanceX.Amount) + require.Equal(t, sdk.ZeroInt(), depositorBalanceY.Amount) + require.Equal(t, denomX, depositorBalanceX.Denom) + require.Equal(t, denomY, depositorBalanceY.Denom) + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + depositorBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + depositorBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + require.Equal(t, sdk.ZeroInt(), depositorBalanceX.Amount) + require.Equal(t, sdk.ZeroInt(), depositorBalanceY.Amount) + require.Equal(t, denomX, depositorBalanceX.Denom) + require.Equal(t, denomY, depositorBalanceY.Denom) + // msg deleted + _, found = simapp.LiquidityKeeper.GetPoolBatchDepositMsgState(ctx, poolID, msgs[0].MsgIndex) + require.False(t, found) + + msgs = simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, batch) + require.Len(t, msgs, 0) + + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, batch.PoolId) + require.True(t, found) + require.Equal(t, uint64(2), batch.Index) + + // withdraw + withdrawerBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + withdrawerBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + withdrawerBalancePoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) + moduleAccEscrowAmtPool := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, pools[0].PoolCoinDenom) + require.Equal(t, sdk.ZeroInt(), moduleAccEscrowAmtPool.Amount) + withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[1], poolID, withdrawerBalancePoolCoinBefore) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + require.NoError(t, err) + + withdrawerBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + withdrawerBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + withdrawerBalancePoolCoin := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) + poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + require.Equal(t, sdk.ZeroInt(), withdrawerBalanceX.Amount) + require.Equal(t, sdk.ZeroInt(), withdrawerBalanceY.Amount) + require.Equal(t, sdk.ZeroInt(), withdrawerBalancePoolCoin.Amount) + require.Equal(t, poolCoin, creatorBalance.Amount.Add(depositorPoolCoinBalance.Amount)) + + // check escrow balance of module account + moduleAccEscrowAmtPool = simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, pools[0].PoolCoinDenom) + require.Equal(t, withdrawerBalancePoolCoinBefore, moduleAccEscrowAmtPool) + + // endblock + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + // verify burned pool coin + poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + withdrawerBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + withdrawerBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + withdrawerBalancePoolCoin = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) + require.Equal(t, depositX.Amount.ToDec().Mul(sdk.OneDec().Sub(params.WithdrawFeeRate)).TruncateInt(), withdrawerBalanceX.Amount) + require.Equal(t, depositY.Amount.ToDec().Mul(sdk.OneDec().Sub(params.WithdrawFeeRate)).TruncateInt(), withdrawerBalanceY.Amount) + require.Equal(t, sdk.ZeroInt(), withdrawerBalancePoolCoin.Amount) + require.Equal(t, poolCoin, creatorBalance.Amount) + + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + withdrawMsgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Len(t, withdrawMsgs, 1) + require.True(t, withdrawMsgs[0].Executed) + require.True(t, withdrawMsgs[0].Succeeded) + require.True(t, withdrawMsgs[0].ToBeDeleted) + require.Equal(t, uint64(2), batch.Index) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // msg deleted + withdrawMsgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Len(t, withdrawMsgs, 0) + _, found = simapp.LiquidityKeeper.GetPoolBatchWithdrawMsgState(ctx, poolID, 0) + require.False(t, found) + + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, batch.PoolId) + require.True(t, found) + require.Equal(t, uint64(3), batch.Index) + require.False(t, batch.Executed) +} + +func TestCreateDepositWithdrawWithinBatch2(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(1000000000) + deposit := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) + deposit2 := sdk.NewCoins(sdk.NewCoin(denomX, X.QuoRaw(2)), sdk.NewCoin(denomY, Y.QuoRaw(2))) + + // set accounts for creator, depositor, withdrawer, balance for deposit + params := simapp.LiquidityKeeper.GetParams(ctx) + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + app.SaveAccount(simapp, ctx, addrs[0], deposit) // pool creator + depositX := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomX) + depositY := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomY) + depositBalance := sdk.NewCoins(depositX, depositY) + require.Equal(t, deposit, depositBalance) + + // create Liquidity pool + poolTypeID := types.DefaultPoolTypeID + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + // verify created liquidity pool + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + poolID := pools[0].Id + require.Equal(t, 1, len(pools)) + require.Equal(t, uint64(1), poolID) + require.Equal(t, denomX, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomY, pools[0].ReserveCoinDenoms[1]) + + // verify minted pool coin + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + // begin block, init + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // set pool depositor account + app.SaveAccount(simapp, ctx, addrs[1], deposit2) // pool creator + depositX = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomX) + depositY = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomY) + depositBalance = sdk.NewCoins(depositX, depositY) + require.Equal(t, deposit2, depositBalance) + + depositMsg := types.NewMsgDepositWithinBatch(addrs[1], poolID, depositBalance) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + depositorBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + depositorBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + require.Equal(t, sdk.ZeroInt(), depositorBalanceX.Amount) + require.Equal(t, sdk.ZeroInt(), depositorBalanceY.Amount) + require.Equal(t, denomX, depositorBalanceX.Denom) + require.Equal(t, denomY, depositorBalanceY.Denom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + // check escrow balance of module account + moduleAccAddress := simapp.AccountKeeper.GetModuleAddress(types.ModuleName) + moduleAccEscrowAmtX := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, denomX) + moduleAccEscrowAmtY := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, denomY) + require.Equal(t, depositX, moduleAccEscrowAmtX) + require.Equal(t, depositY, moduleAccEscrowAmtY) + + // endblock + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + // verify minted pool coin + poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + depositorPoolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) + require.NotEqual(t, sdk.ZeroInt(), depositBalance) + require.Equal(t, poolCoin, depositorPoolCoinBalance.Amount.Add(creatorBalance.Amount)) + + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, batch) + require.Len(t, msgs, 1) + require.True(t, msgs[0].Executed) + require.True(t, msgs[0].Succeeded) + require.True(t, msgs[0].ToBeDeleted) + require.Equal(t, uint64(1), batch.Index) + + // error balance after endblock + depositorBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + depositorBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + require.Equal(t, sdk.ZeroInt(), depositorBalanceX.Amount) + require.Equal(t, sdk.ZeroInt(), depositorBalanceY.Amount) + require.Equal(t, denomX, depositorBalanceX.Denom) + require.Equal(t, denomY, depositorBalanceY.Denom) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + depositorBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + depositorBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + require.Equal(t, sdk.ZeroInt(), depositorBalanceX.Amount) + require.Equal(t, sdk.ZeroInt(), depositorBalanceY.Amount) + require.Equal(t, denomX, depositorBalanceX.Denom) + require.Equal(t, denomY, depositorBalanceY.Denom) + // msg deleted + _, found = simapp.LiquidityKeeper.GetPoolBatchDepositMsgState(ctx, poolID, msgs[0].MsgIndex) + require.False(t, found) + + msgs = simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, batch) + require.Len(t, msgs, 0) + + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, batch.PoolId) + require.True(t, found) + require.Equal(t, uint64(2), batch.Index) + + // withdraw + withdrawerBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + withdrawerBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + withdrawerBalancePoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) + moduleAccEscrowAmtPool := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, pools[0].PoolCoinDenom) + require.Equal(t, sdk.ZeroInt(), moduleAccEscrowAmtPool.Amount) + withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[1], poolID, withdrawerBalancePoolCoinBefore) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + require.NoError(t, err) + + withdrawerBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + withdrawerBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + withdrawerBalancePoolCoin := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) + poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + require.Equal(t, sdk.ZeroInt(), withdrawerBalanceX.Amount) + require.Equal(t, sdk.ZeroInt(), withdrawerBalanceY.Amount) + require.Equal(t, sdk.ZeroInt(), withdrawerBalancePoolCoin.Amount) + require.Equal(t, poolCoin, creatorBalance.Amount.Add(depositorPoolCoinBalance.Amount)) + + // check escrow balance of module account + moduleAccEscrowAmtPool = simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, pools[0].PoolCoinDenom) + require.Equal(t, withdrawerBalancePoolCoinBefore, moduleAccEscrowAmtPool) + + // endblock + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + // verify burned pool coin + poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + withdrawerBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + withdrawerBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + withdrawerBalancePoolCoin = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) + require.Equal(t, depositX.Amount.ToDec().Mul(sdk.OneDec().Sub(params.WithdrawFeeRate)).TruncateInt(), withdrawerBalanceX.Amount) + require.Equal(t, depositY.Amount.ToDec().Mul(sdk.OneDec().Sub(params.WithdrawFeeRate)).TruncateInt(), withdrawerBalanceY.Amount) + require.Equal(t, sdk.ZeroInt(), withdrawerBalancePoolCoin.Amount) + require.Equal(t, poolCoin, creatorBalance.Amount) + + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + withdrawMsgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Len(t, withdrawMsgs, 1) + require.True(t, withdrawMsgs[0].Executed) + require.True(t, withdrawMsgs[0].Succeeded) + require.True(t, withdrawMsgs[0].ToBeDeleted) + require.Equal(t, uint64(2), batch.Index) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // msg deleted + withdrawMsgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Len(t, withdrawMsgs, 0) + _, found = simapp.LiquidityKeeper.GetPoolBatchWithdrawMsgState(ctx, poolID, 0) + require.False(t, found) + + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, batch.PoolId) + require.True(t, found) + require.Equal(t, uint64(3), batch.Index) + require.False(t, batch.Executed) +} + +// This scenario tests simple create pool, deposit to the pool, and withdraw from the pool +func TestLiquidityScenario(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(1000000000) + + // create 20 random accounts with an initial balance of 0.01 + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + // create two pools with the different denomY of 1000X and 1000Y coins + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + poolId2 := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, "testDenom", addrs[0]) + require.Equal(t, uint64(1), poolID) + require.Equal(t, uint64(2), poolId2) + + app.TestDepositPool(t, simapp, ctx, X, Y, addrs[1:10], poolID, true) + + // next block starts + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + _, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + + // deposit message is expected to be handled + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, batch) + require.Len(t, msgs, 0) + + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(500000), addrs[1:10], poolID, true) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // withdraw message is expected to be handled + withdrawMsgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Len(t, withdrawMsgs, 0) + + _, found = simapp.LiquidityKeeper.GetPoolBatchWithdrawMsgState(ctx, poolID, 0) + require.False(t, found) + + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, batch.PoolId) + require.True(t, found) + require.Equal(t, uint64(3), batch.Index) + require.False(t, batch.Executed) +} + +// This scenario tests create pool, deposit to the pool, and swap coins +func TestLiquidityScenario2(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(1000000000) + + // create 20 random accounts with an initial balance of 0.01 + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + // create pool with 1000X and 1000Y coins + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + require.Equal(t, uint64(1), poolID) + + // make two different deposits to the same pool with different amounts of coins + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, true) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, true) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + price, _ := sdk.NewDecFromStr("1.1") + + offerCoinList := []sdk.Coin{sdk.NewCoin(denomX, sdk.NewInt(10000))} + orderPriceList := []sdk.Dec{price} + orderAddrList := addrs[1:2] + + app.TestSwapPool(t, simapp, ctx, offerCoinList, orderPriceList, orderAddrList, poolID, false) + app.TestSwapPool(t, simapp, ctx, offerCoinList, orderPriceList, orderAddrList, poolID, false) + app.TestSwapPool(t, simapp, ctx, offerCoinList, orderPriceList, orderAddrList, poolID, false) + app.TestSwapPool(t, simapp, ctx, offerCoinList, orderPriceList, orderAddrList, poolID, true) +} + +// This scenario tests to executed accumulated deposit and withdraw pool batches +func TestLiquidityScenario3(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(500000000) + + // create 20 random accounts with an initial balance of 0.01 + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + // create pool with 1000X and 500Y coins + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + // make 6 different deposits to the same pool with different amounts of coins + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + + // execute accumulated deposit batches + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(5000), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(500), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(50), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(5000), addrs[2:3], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(500), addrs[2:3], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(50), addrs[2:3], poolID, false) + + // execute accumulated withdraw batches + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) +} + +// This scenario tests deposit refund scenario +func TestDepositRefundTooSmallDepositAmount(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(500000000) + + // create 20 random accounts with an initial balance of 0.01 + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + // create pool with 1000X and 500Y coins + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + app.TestDepositPool(t, simapp, ctx, sdk.OneInt(), sdk.OneInt(), addrs[1:2], poolID, false) + + // balance should be zero since accounts' balances are expected to be in an escrow account + balanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomX) + balanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomY) + require.Equal(t, sdk.ZeroInt(), balanceX.Amount) + require.Equal(t, sdk.ZeroInt(), balanceY.Amount) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + balanceXRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomX) + balanceYRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomY) + require.True(sdk.IntEq(t, sdk.OneInt(), balanceXRefunded.Amount)) + require.True(sdk.IntEq(t, sdk.OneInt(), balanceYRefunded.Amount)) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) +} + +// This scenario tests deposit refund scenario +func TestDepositRefundDeletedPool(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(500000000) + + // create 20 random accounts with an initial balance of 0.01 + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + // create pool with 1000X and 500Y coins + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + app.TestDepositPool(t, simapp, ctx, X, Y, addrs[1:2], poolID, false) + + // balance should be zero since accounts' balances are expected to be in an escrow account + balanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomX) + balanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomY) + require.Equal(t, sdk.ZeroInt(), balanceX.Amount) + require.Equal(t, sdk.ZeroInt(), balanceY.Amount) + + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + // delete previously created pool + simapp.LiquidityKeeper.DeletePool(ctx, pool) + + pool, found = simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.False(t, found) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + balanceXRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomX) + balanceYRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomY) + require.True(sdk.IntEq(t, X, balanceXRefunded.Amount)) + require.True(sdk.IntEq(t, Y, balanceYRefunded.Amount)) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) +} + +// This scenario tests refund withdraw scenario +func TestLiquidityScenario5(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(500000000) + + // create 20 random accounts with an initial balance of 0.01 + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + // create pool with 1000X and 500Y coins + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + poolCoin := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + // withdraw all pool coin from the pool + app.TestWithdrawPool(t, simapp, ctx, poolCoin.Amount, addrs[0:1], poolID, false) + + poolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.Equal(t, sdk.ZeroInt(), poolCoinAfter.Amount) + + // save pool coin denom before deleting the pool + poolCoinDenom := pool.PoolCoinDenom + + // delete the pool + simapp.LiquidityKeeper.DeletePool(ctx, pool) + + pool, found = simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.False(t, found) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + // pool coin should be refunded since the pool is deleted before executing pool batch + poolCoinRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[0], poolCoinDenom) + require.Equal(t, poolCoin.Amount, poolCoinRefunded.Amount) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) +} + +// This scenario tests pool coin and refunded amounts after depositing X and Y amounts of coins +// - 100X and 200Y in reserve pool +// - deposit 30X and 20Y coins +// - test how many pool coins to receive +// - test how many X or Y coins to be refunded +func TestLiquidityScenario6(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(100000000) + Y := sdk.NewInt(200000000) + + // create 20 random accounts with an initial balance of 0.01 + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + // create pool with 100X and 200Y coins + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + poolCoinTotalSupply := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + + // use the other account to make deposit to the pool with 30X and 20Y coins + app.TestDepositPool(t, simapp, ctx, sdk.NewInt(30000000), sdk.NewInt(20000000), addrs[1:2], poolID, false) + + // execute pool batch + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + poolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) + require.Equal(t, sdk.NewInt(100000), poolCoinBalance.Amount) + require.Equal(t, poolCoinTotalSupply.QuoRaw(10), poolCoinBalance.Amount) + + balanceXRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomX) + balanceYRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomY) + require.Equal(t, sdk.NewInt(20000000), balanceXRefunded.Amount) + require.Equal(t, sdk.ZeroInt(), balanceYRefunded.Amount) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) +} + +// This scenario is similar with scenario6 +// Depositing different amounts will result in different amount of refunded amounts +// - 100X and 200Y in reserve pool +// - deposit 10X and 30Y coins +// - test how many pool coins to receive +// - test how many X or Y coins to be refunded +func TestLiquidityScenario7(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(100000000) + Y := sdk.NewInt(200000000) + + // create 20 random accounts with an initial balance of 0.01 + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + // create pool with 100X and 200Y coins + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + poolCoinTotalSupply := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + + // use the other account to make deposit to the pool with 10X and 30Y coins + app.TestDepositPool(t, simapp, ctx, sdk.NewInt(10000000), sdk.NewInt(30000000), addrs[1:2], poolID, false) + + // execute pool batch + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + poolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) + require.Equal(t, sdk.NewInt(100000), poolCoinBalance.Amount) + require.Equal(t, poolCoinTotalSupply.QuoRaw(10), poolCoinBalance.Amount) + + balanceXRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomX) + balanceYRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomY) + require.Equal(t, sdk.ZeroInt(), balanceXRefunded.Amount) + require.Equal(t, sdk.NewInt(10000000), balanceYRefunded.Amount) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) +} + +// This scenario tests to withdraw amounts from reserve pool to see the impacts of how pool coin and account's balance. +// - 100X and 200Y in reserve pool +// - withdraw 10th of pool coin total supply +// - test pool coin total supply +// - test account's coin balance +func TestLiquidityScenario8(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(100000000) + Y := sdk.NewInt(200000000) + + // create 20 random accounts with an initial balance of 0.01 + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + // create pool with 100X and 200Y coins + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + poolCoinTotalSupply := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + + poolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.Equal(t, sdk.NewInt(1000000), poolCoinTotalSupply) + require.Equal(t, sdk.NewInt(1000000), poolCoinBalance.Amount) + + // withdraw 10th of poolCoinTotalSupply from the pool + app.TestWithdrawPool(t, simapp, ctx, poolCoinTotalSupply.QuoRaw(10), addrs[0:1], poolID, false) + + // execute pool batch + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + poolCoinTotalSupply = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + + poolCoinBalance = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.Equal(t, sdk.NewInt(900000), poolCoinTotalSupply) + require.Equal(t, sdk.NewInt(900000), poolCoinBalance.Amount) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) +} + +// Test UnitBatchHeight when over 1 +func TestLiquidityUnitBatchHeight(t *testing.T) { + simapp, ctx := createTestInput() + ctx = ctx.WithBlockHeight(1) + + params := simapp.LiquidityKeeper.GetParams(ctx) + params.UnitBatchHeight = 2 + simapp.LiquidityKeeper.SetParams(ctx, params) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(100000000) + Y := sdk.NewInt(200000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + poolCoins := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + poolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.Equal(t, sdk.NewInt(1000000), poolCoins) + require.Equal(t, sdk.NewInt(1000000), poolCoinBalance.Amount) + app.TestWithdrawPool(t, simapp, ctx, poolCoins.QuoRaw(10), addrs[0:1], poolID, false) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + + // batch not executed, 1 >= 2(UnitBatchHeight) + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, pool.Id) + require.True(t, found) + require.False(t, batch.Executed) + batchWithdrawMsgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Equal(t, 1, len(batchWithdrawMsgs)) + + poolCoins = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + poolCoinBalance = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.Equal(t, sdk.NewInt(1000000), poolCoins) + require.Equal(t, sdk.NewInt(900000), poolCoinBalance.Amount) + + // next block + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + batchWithdrawMsgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Equal(t, 1, len(batchWithdrawMsgs)) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + + // batch executed, 2 >= 2(UnitBatchHeight) + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, pool.Id) + require.True(t, found) + require.True(t, batch.Executed) + batchWithdrawMsgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Equal(t, 1, len(batchWithdrawMsgs)) + + poolCoins = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + poolCoinBalance = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.Equal(t, sdk.NewInt(900000), poolCoins) + require.Equal(t, sdk.NewInt(900000), poolCoinBalance.Amount) + + // next block + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // batch msg deleted after batch execution + batchWithdrawMsgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Equal(t, 0, len(batchWithdrawMsgs)) +} + +func TestInitNextBatch(t *testing.T) { + simapp, ctx := createTestInput() + pool := types.Pool{ + Id: 1, + TypeId: 1, + ReserveCoinDenoms: nil, + ReserveAccountAddress: "", + PoolCoinDenom: "", + } + simapp.LiquidityKeeper.SetPool(ctx, pool) + + batch := types.NewPoolBatch(pool.Id, 1) + + simapp.LiquidityKeeper.SetPoolBatch(ctx, batch) + err := simapp.LiquidityKeeper.InitNextPoolBatch(ctx, batch) + require.ErrorIs(t, err, types.ErrBatchNotExecuted) + + batch.Executed = true + simapp.LiquidityKeeper.SetPoolBatch(ctx, batch) + + err = simapp.LiquidityKeeper.InitNextPoolBatch(ctx, batch) + require.NoError(t, err) + + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, batch.PoolId) + require.True(t, found) + require.False(t, batch.Executed) + require.Equal(t, uint64(2), batch.Index) +} + +func TestDeleteAndInitPoolBatchDeposit(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(500000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + + depositsAll := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, batch) + require.Equal(t, 6, len(depositsAll)) + depositsAll[0].Executed = true + depositsAll[0].ToBeDeleted = false + simapp.LiquidityKeeper.SetPoolBatchDepositMsgStates(ctx, poolID, depositsAll) + depositsRemaining := simapp.LiquidityKeeper.GetAllRemainingPoolBatchDepositMsgStates(ctx, batch) + batch.Executed = true + simapp.LiquidityKeeper.SetPoolBatch(ctx, batch) + simapp.LiquidityKeeper.DeleteAndInitPoolBatches(ctx) + depositsAfter := simapp.LiquidityKeeper.GetAllRemainingPoolBatchDepositMsgStates(ctx, batch) + + require.Equal(t, 1, len(depositsRemaining)) + require.Equal(t, 0, len(depositsAfter)) + + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) +} + +func TestDeleteAndInitPoolBatchWithdraw(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(500000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(5000), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(500), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(50), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(5000), addrs[2:3], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(500), addrs[2:3], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(50), addrs[2:3], poolID, false) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + + withdrawsAll := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.Equal(t, 6, len(withdrawsAll)) + withdrawsAll[0].Executed = true + withdrawsAll[0].ToBeDeleted = false + simapp.LiquidityKeeper.SetPoolBatchWithdrawMsgStates(ctx, poolID, withdrawsAll) + withdrawsRemaining := simapp.LiquidityKeeper.GetAllRemainingPoolBatchWithdrawMsgStates(ctx, batch) + batch.Executed = true + simapp.LiquidityKeeper.SetPoolBatch(ctx, batch) + simapp.LiquidityKeeper.DeleteAndInitPoolBatches(ctx) + withdrawsAfter := simapp.LiquidityKeeper.GetAllRemainingPoolBatchWithdrawMsgStates(ctx, batch) + require.Equal(t, 1, len(withdrawsRemaining)) + require.Equal(t, 0, len(withdrawsAfter)) + + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) +} + +func TestUnitBatchHeight(t *testing.T) { + for _, unitBatchHeight := range []uint32{1, 2, 3, 5, 9} { + simapp, ctx := createTestInput() + ctx = ctx.WithBlockHeight(1) + params := simapp.LiquidityKeeper.GetParams(ctx) + params.UnitBatchHeight = unitBatchHeight + simapp.LiquidityKeeper.SetParams(ctx, params) + + X, Y := sdk.NewInt(1000000), sdk.NewInt(1000000) + pool, err := createPool(simapp, ctx, X, Y, DenomX, DenomY) + require.NoError(t, err) + + johnCoins := sdk.NewCoins( + sdk.NewInt64Coin(DenomX, 100000000), sdk.NewInt64Coin(DenomY, 100000000)) + johnAddr := app.AddRandomTestAddr(simapp, ctx, johnCoins) + + for ; ctx.BlockHeight() <= 100; ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) { + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + batch, ok := simapp.LiquidityKeeper.GetPoolBatch(ctx, pool.Id) + require.True(t, ok) + require.False(t, batch.Executed, "batch should not be executed") + require.Equal( + t, (ctx.BlockHeight()-1)/int64(unitBatchHeight)*int64(unitBatchHeight)+1, batch.BeginHeight) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch( + ctx, types.NewMsgSwapWithinBatch( + johnAddr, pool.Id, types.DefaultSwapTypeID, + sdk.NewInt64Coin(DenomX, 1000), DenomY, sdk.MustNewDecFromStr("1.1"), + params.SwapFeeRate), 0) + require.NoError(t, err) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + batch, ok = simapp.LiquidityKeeper.GetPoolBatch(ctx, pool.Id) + require.True(t, ok) + if ctx.BlockHeight()%int64(unitBatchHeight) == 0 { + require.True(t, batch.Executed, "batch should be executed") + } else { + require.False(t, batch.Executed, "batch should not be executed") + } + require.Equal( + t, (ctx.BlockHeight()-1)/int64(unitBatchHeight)*int64(unitBatchHeight)+1, batch.BeginHeight) + } + } +} + +func TestSwapAutoOrderExpiryHeight(t *testing.T) { + simapp, ctx, pool, _, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1000000)) + require.NoError(t, err) + ctx = ctx.WithBlockHeight(1) + params := simapp.LiquidityKeeper.GetParams(ctx) + params.UnitBatchHeight = 5 + simapp.LiquidityKeeper.SetParams(ctx, params) + + addr := app.AddRandomTestAddr(simapp, ctx, sdk.NewCoins(sdk.NewInt64Coin(DenomX, 1000000))) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + orderPrice := sdk.MustNewDecFromStr("2") + sms, err := simapp.LiquidityKeeper.SwapWithinBatch( + ctx, + types.NewMsgSwapWithinBatch( + addr, pool.Id, types.DefaultSwapTypeID, sdk.NewInt64Coin(DenomX, 100000), DenomY, orderPrice, params.SwapFeeRate), + types.CancelOrderLifeSpan) + require.NoError(t, err) + require.Equal(t, int64(5), sms.OrderExpiryHeight) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + ctx = ctx.WithBlockHeight(4) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + balances := simapp.BankKeeper.GetAllBalances(ctx, addr) + require.True(t, balances.AmountOf(DenomX).Equal(sdk.NewInt(1000000-100150))) + require.True(t, balances.AmountOf(DenomY).IsZero()) + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, pool.Id) + require.True(t, found) + states := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStates(ctx, batch) + require.Len(t, states, 1) + + ctx = ctx.WithBlockHeight(5) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + balances = simapp.BankKeeper.GetAllBalances(ctx, addr) + require.True(t, !balances.AmountOf(DenomY).IsZero()) // Check if swap request has executed + ctx = ctx.WithBlockHeight(6) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + states = simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStates(ctx, batch) + require.Len(t, states, 0) +} diff --git a/x/liquidity/keeper/common_test.go b/x/liquidity/keeper/common_test.go new file mode 100644 index 00000000000..0408e49116e --- /dev/null +++ b/x/liquidity/keeper/common_test.go @@ -0,0 +1,94 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// createTestInput Returns a simapp with custom LiquidityKeeper +// to avoid messing with the hooks. +func createTestInput() (*app.LiquidityApp, sdk.Context) { + return app.CreateTestInput() +} + +func createLiquidity(t *testing.T, ctx sdk.Context, simapp *app.LiquidityApp) ( + []sdk.AccAddress, []types.Pool, []types.PoolBatch, + []types.DepositMsgState, []types.WithdrawMsgState, +) { + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + denomA, denomB := types.AlphabeticalDenomPair("denomA", "denomB") + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(500000000) + A := sdk.NewInt(500000000) + B := sdk.NewInt(1000000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + app.TestCreatePool(t, simapp, ctx, A, B, denomA, denomB, addrs[1]) + + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + price, _ := sdk.NewDecFromStr("1.1") + priceY, _ := sdk.NewDecFromStr("1.2") + xOfferCoins := []sdk.Coin{sdk.NewCoin(denomX, sdk.NewInt(10000))} + yOfferCoins := []sdk.Coin{sdk.NewCoin(denomY, sdk.NewInt(5000))} + xOrderPrices := []sdk.Dec{price} + yOrderPrices := []sdk.Dec{priceY} + xOrderAddrs := addrs[1:2] + yOrderAddrs := addrs[2:3] + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(50), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(500), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(50), addrs[2:3], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(500), addrs[2:3], poolID, false) + + app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, yOfferCoins, yOrderPrices, yOrderAddrs, poolID, false) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + batches := simapp.LiquidityKeeper.GetAllPoolBatches(ctx) + depositMsgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, batches[0]) + withdrawMsgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batches[0]) + return addrs, pools, batches, depositMsgs, withdrawMsgs +} + +func createTestPool(X, Y sdk.Coin) (*app.LiquidityApp, sdk.Context, types.Pool, sdk.AccAddress, error) { + simapp, ctx := createTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + depositCoins := sdk.NewCoins(X, Y) + creatorAddr := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) + + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creatorAddr, types.DefaultPoolTypeID, depositCoins)) + if err != nil { + return nil, sdk.Context{}, types.Pool{}, sdk.AccAddress{}, err + } + + return simapp, ctx, pool, creatorAddr, nil +} diff --git a/x/liquidity/keeper/genesis.go b/x/liquidity/keeper/genesis.go new file mode 100644 index 00000000000..54e3a606365 --- /dev/null +++ b/x/liquidity/keeper/genesis.go @@ -0,0 +1,61 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// InitGenesis initializes the liquidity module's state from a given genesis state. +func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { + if err := k.ValidateGenesis(ctx, genState); err != nil { + panic(err) + } + + k.SetParams(ctx, genState.Params) + + for _, record := range genState.PoolRecords { + k.SetPoolRecord(ctx, record) + } +} + +// ExportGenesis returns the liquidity module's genesis state. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + params := k.GetParams(ctx) + + var poolRecords []types.PoolRecord + + pools := k.GetAllPools(ctx) + + for _, pool := range pools { + record, found := k.GetPoolRecord(ctx, pool) + if found { + poolRecords = append(poolRecords, record) + } + } + + if len(poolRecords) == 0 { + poolRecords = []types.PoolRecord{} + } + + return types.NewGenesisState(params, poolRecords) +} + +// ValidateGenesis validates the liquidity module's genesis state. +func (k Keeper) ValidateGenesis(ctx sdk.Context, genState types.GenesisState) error { + if err := genState.Params.Validate(); err != nil { + return err + } + + cc, _ := ctx.CacheContext() + k.SetParams(cc, genState.Params) + + for _, record := range genState.PoolRecords { + record = k.SetPoolRecord(cc, record) + if err := k.ValidatePoolRecord(cc, record); err != nil { + return err + } + } + + return nil +} diff --git a/x/liquidity/keeper/genesis_test.go b/x/liquidity/keeper/genesis_test.go new file mode 100644 index 00000000000..2a2f52f8076 --- /dev/null +++ b/x/liquidity/keeper/genesis_test.go @@ -0,0 +1,138 @@ +package keeper_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestGenesis(t *testing.T) { + simapp, ctx := app.CreateTestInput() + + lk := simapp.LiquidityKeeper + + // default genesis state + genState := types.DefaultGenesisState() + require.Equal(t, sdk.NewDecWithPrec(3, 3), genState.Params.SwapFeeRate) + + // change swap fee rate + params := lk.GetParams(ctx) + params.SwapFeeRate = sdk.NewDecWithPrec(5, 3) + + // set params + lk.SetParams(ctx, params) + + newGenState := lk.ExportGenesis(ctx) + require.Equal(t, sdk.NewDecWithPrec(5, 3), newGenState.Params.SwapFeeRate) + + fmt.Println("newGenState: ", newGenState) +} + +func TestGenesisState(t *testing.T) { + simapp, ctx := app.CreateTestInput() + + params := simapp.LiquidityKeeper.GetParams(ctx) + paramsDefault := simapp.LiquidityKeeper.GetParams(ctx) + genesis := types.DefaultGenesisState() + + invalidDenom := "invalid denom---" + invalidDenomErrMsg := fmt.Sprintf("invalid denom: %s", invalidDenom) + params.PoolCreationFee = sdk.Coins{sdk.Coin{Denom: invalidDenom, Amount: sdk.NewInt(0)}} + require.EqualError(t, params.Validate(), invalidDenomErrMsg) + + params = simapp.LiquidityKeeper.GetParams(ctx) + params.SwapFeeRate = sdk.NewDec(-1) + negativeSwapFeeErrMsg := fmt.Sprintf("swap fee rate must not be negative: %s", params.SwapFeeRate) + genesisState := types.NewGenesisState(params, genesis.PoolRecords) + require.EqualError(t, types.ValidateGenesis(*genesisState), negativeSwapFeeErrMsg) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + X := sdk.NewInt(100_000_000) + Y := sdk.NewInt(200_000_000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10_000)) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + poolCoins := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + app.TestDepositPool(t, simapp, ctx, sdk.NewInt(30_000_000), sdk.NewInt(20_000_000), addrs[1:2], poolID, false) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + poolCoinBalanceCreator := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + poolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) + require.Equal(t, sdk.NewInt(100_000), poolCoinBalance.Amount) + require.Equal(t, poolCoins.QuoRaw(10), poolCoinBalance.Amount) + + balanceXRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomX) + balanceYRefunded := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomY) + require.Equal(t, sdk.NewInt(20000000), balanceXRefunded.Amount) + require.Equal(t, sdk.ZeroInt(), balanceYRefunded.Amount) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // validate pool records + newGenesis := simapp.LiquidityKeeper.ExportGenesis(ctx) + genesisState = types.NewGenesisState(paramsDefault, newGenesis.PoolRecords) + require.NoError(t, types.ValidateGenesis(*genesisState)) + + pool.TypeId = 5 + simapp.LiquidityKeeper.SetPool(ctx, pool) + newGenesisBrokenPool := simapp.LiquidityKeeper.ExportGenesis(ctx) + require.NoError(t, types.ValidateGenesis(*newGenesisBrokenPool)) + require.Equal(t, 1, len(newGenesisBrokenPool.PoolRecords)) + + err := simapp.LiquidityKeeper.ValidatePoolRecord(ctx, newGenesisBrokenPool.PoolRecords[0]) + require.ErrorIs(t, err, types.ErrPoolTypeNotExists) + + // not initialized genState of other module (auth, bank, ... ) only liquidity module + reserveCoins := simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.Equal(t, 2, len(reserveCoins)) + simapp2 := app.Setup(false) + ctx2 := simapp2.BaseApp.NewContext(false, tmproto.Header{}) + require.Panics(t, func() { + simapp2.LiquidityKeeper.InitGenesis(ctx2, *newGenesis) + }) + require.Panics(t, func() { + app.SaveAccount(simapp2, ctx, pool.GetReserveAccount(), reserveCoins) + simapp2.LiquidityKeeper.InitGenesis(ctx2, *newGenesis) + }) + require.Panics(t, func() { + app.SaveAccount(simapp2, ctx, addrs[0], sdk.Coins{poolCoinBalanceCreator}) + simapp2.LiquidityKeeper.InitGenesis(ctx2, *newGenesis) + }) + require.Panics(t, func() { + app.SaveAccount(simapp2, ctx2, addrs[1], sdk.Coins{poolCoinBalance}) + simapp2.LiquidityKeeper.InitGenesis(ctx2, *newGenesis) + }) + + simapp3 := app.Setup(false) + ctx3 := simapp3.BaseApp.NewContext(false, tmproto.Header{}).WithBlockHeight(ctx.BlockHeight()) + require.Panics(t, func() { + simapp3.LiquidityKeeper.InitGenesis(ctx3, *newGenesis) + }) + require.Panics(t, func() { + app.SaveAccount(simapp3, ctx, pool.GetReserveAccount(), reserveCoins) + simapp3.LiquidityKeeper.InitGenesis(ctx3, *newGenesis) + }) + require.Panics(t, func() { + app.SaveAccount(simapp3, ctx, addrs[0], sdk.Coins{poolCoinBalanceCreator}) + simapp3.LiquidityKeeper.InitGenesis(ctx3, *newGenesis) + }) + require.Panics(t, func() { + app.SaveAccount(simapp3, ctx3, addrs[1], sdk.Coins{poolCoinBalance}) + simapp3.LiquidityKeeper.InitGenesis(ctx3, *newGenesis) + }) +} diff --git a/x/liquidity/keeper/grpc_query.go b/x/liquidity/keeper/grpc_query.go new file mode 100644 index 00000000000..e15b0227c0d --- /dev/null +++ b/x/liquidity/keeper/grpc_query.go @@ -0,0 +1,327 @@ +package keeper + +// DONTCOVER +// client is excluded from test coverage in the poc phase milestone 1 and will be included in milestone 2 with completeness + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// Querier is used as Keeper will have duplicate methods if used directly, and gRPC names take precedence over keeper. +type Querier struct { + Keeper +} + +var _ types.QueryServer = Querier{} + +// LiquidityPool queries a liquidity pool with the given pool id. +func (k Querier) LiquidityPool(c context.Context, req *types.QueryLiquidityPoolRequest) (*types.QueryLiquidityPoolResponse, error) { + empty := &types.QueryLiquidityPoolRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + pool, found := k.GetPool(ctx, req.PoolId) + if !found { + return nil, status.Errorf(codes.NotFound, "liquidity pool %d doesn't exist", req.PoolId) + } + + return k.MakeQueryLiquidityPoolResponse(pool) +} + +// LiquidityPool queries a liquidity pool with the given pool coin denom. +func (k Querier) LiquidityPoolByPoolCoinDenom(c context.Context, req *types.QueryLiquidityPoolByPoolCoinDenomRequest) (*types.QueryLiquidityPoolResponse, error) { + empty := &types.QueryLiquidityPoolByPoolCoinDenomRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(c) + reserveAcc, err := types.GetReserveAcc(req.PoolCoinDenom, false) + if err != nil { + return nil, status.Errorf(codes.NotFound, "liquidity pool with pool coin denom %s doesn't exist", req.PoolCoinDenom) + } + pool, found := k.GetPoolByReserveAccIndex(ctx, reserveAcc) + if !found { + return nil, status.Errorf(codes.NotFound, "liquidity pool with pool coin denom %s doesn't exist", req.PoolCoinDenom) + } + return k.MakeQueryLiquidityPoolResponse(pool) +} + +// LiquidityPool queries a liquidity pool with the given reserve account address. +func (k Querier) LiquidityPoolByReserveAcc(c context.Context, req *types.QueryLiquidityPoolByReserveAccRequest) (*types.QueryLiquidityPoolResponse, error) { + empty := &types.QueryLiquidityPoolByReserveAccRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(c) + reserveAcc, err := sdk.AccAddressFromBech32(req.ReserveAcc) + if err != nil { + return nil, status.Errorf(codes.NotFound, "the reserve account address %s is not valid", req.ReserveAcc) + } + pool, found := k.GetPoolByReserveAccIndex(ctx, reserveAcc) + if !found { + return nil, status.Errorf(codes.NotFound, "liquidity pool with pool reserve account %s doesn't exist", req.ReserveAcc) + } + return k.MakeQueryLiquidityPoolResponse(pool) +} + +// LiquidityPoolBatch queries a liquidity pool batch with the given pool id. +func (k Querier) LiquidityPoolBatch(c context.Context, req *types.QueryLiquidityPoolBatchRequest) (*types.QueryLiquidityPoolBatchResponse, error) { + empty := &types.QueryLiquidityPoolBatchRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + batch, found := k.GetPoolBatch(ctx, req.PoolId) + if !found { + return nil, status.Errorf(codes.NotFound, "liquidity pool batch %d doesn't exist", req.PoolId) + } + + return &types.QueryLiquidityPoolBatchResponse{ + Batch: batch, + }, nil +} + +// Pools queries all liquidity pools currently existed with each liquidity pool with batch and metadata. +func (k Querier) LiquidityPools(c context.Context, req *types.QueryLiquidityPoolsRequest) (*types.QueryLiquidityPoolsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + + store := ctx.KVStore(k.storeKey) + poolStore := prefix.NewStore(store, types.PoolKeyPrefix) + + var pools types.Pools + + pageRes, err := query.Paginate(poolStore, req.Pagination, func(key []byte, value []byte) error { + pool, err := types.UnmarshalPool(k.cdc, value) + if err != nil { + return err + } + pools = append(pools, pool) + return nil + }) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + if len(pools) == 0 { + return nil, status.Error(codes.NotFound, "There are no pools present.") + } + + return &types.QueryLiquidityPoolsResponse{ + Pools: pools, + Pagination: pageRes, + }, nil +} + +// PoolBatchSwapMsg queries the pool batch swap message with the message index of the liquidity pool. +func (k Querier) PoolBatchSwapMsg(c context.Context, req *types.QueryPoolBatchSwapMsgRequest) (*types.QueryPoolBatchSwapMsgResponse, error) { + empty := &types.QueryPoolBatchSwapMsgRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + msg, found := k.GetPoolBatchSwapMsgState(ctx, req.PoolId, req.MsgIndex) + if !found { + return nil, status.Errorf(codes.NotFound, "the msg given msg_index %d doesn't exist or deleted", req.MsgIndex) + } + + return &types.QueryPoolBatchSwapMsgResponse{ + Swap: msg, + }, nil +} + +// PoolBatchSwapMsgs queries all pool batch swap messages of the liquidity pool. +func (k Querier) PoolBatchSwapMsgs(c context.Context, req *types.QueryPoolBatchSwapMsgsRequest) (*types.QueryPoolBatchSwapMsgsResponse, error) { + empty := &types.QueryPoolBatchSwapMsgsRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + _, found := k.GetPool(ctx, req.PoolId) + if !found { + return nil, status.Errorf(codes.NotFound, "liquidity pool %d doesn't exist", req.PoolId) + } + + store := ctx.KVStore(k.storeKey) + msgStore := prefix.NewStore(store, types.GetPoolBatchSwapMsgStatesPrefix(req.PoolId)) + + var msgs []types.SwapMsgState + + pageRes, err := query.Paginate(msgStore, req.Pagination, func(key []byte, value []byte) error { + msg, err := types.UnmarshalSwapMsgState(k.cdc, value) + if err != nil { + return err + } + + msgs = append(msgs, msg) + + return nil + }) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.QueryPoolBatchSwapMsgsResponse{ + Swaps: msgs, + Pagination: pageRes, + }, nil +} + +// PoolBatchDepositMsg queries the pool batch deposit message with the msg_index of the liquidity pool. +func (k Querier) PoolBatchDepositMsg(c context.Context, req *types.QueryPoolBatchDepositMsgRequest) (*types.QueryPoolBatchDepositMsgResponse, error) { + empty := &types.QueryPoolBatchDepositMsgRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + msg, found := k.GetPoolBatchDepositMsgState(ctx, req.PoolId, req.MsgIndex) + if !found { + return nil, status.Errorf(codes.NotFound, "the msg given msg_index %d doesn't exist or deleted", req.MsgIndex) + } + + return &types.QueryPoolBatchDepositMsgResponse{ + Deposit: msg, + }, nil +} + +// PoolBatchDepositMsgs queries all pool batch deposit messages of the liquidity pool. +func (k Querier) PoolBatchDepositMsgs(c context.Context, req *types.QueryPoolBatchDepositMsgsRequest) (*types.QueryPoolBatchDepositMsgsResponse, error) { + empty := &types.QueryPoolBatchDepositMsgsRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + _, found := k.GetPool(ctx, req.PoolId) + if !found { + return nil, status.Errorf(codes.NotFound, "liquidity pool %d doesn't exist", req.PoolId) + } + + store := ctx.KVStore(k.storeKey) + msgStore := prefix.NewStore(store, types.GetPoolBatchDepositMsgStatesPrefix(req.PoolId)) + var msgs []types.DepositMsgState + + pageRes, err := query.Paginate(msgStore, req.Pagination, func(key []byte, value []byte) error { + msg, err := types.UnmarshalDepositMsgState(k.cdc, value) + if err != nil { + return err + } + + msgs = append(msgs, msg) + + return nil + }) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.QueryPoolBatchDepositMsgsResponse{ + Deposits: msgs, + Pagination: pageRes, + }, nil +} + +// PoolBatchWithdrawMsg queries the pool batch withdraw message with the msg_index of the liquidity pool. +func (k Querier) PoolBatchWithdrawMsg(c context.Context, req *types.QueryPoolBatchWithdrawMsgRequest) (*types.QueryPoolBatchWithdrawMsgResponse, error) { + empty := &types.QueryPoolBatchWithdrawMsgRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + msg, found := k.GetPoolBatchWithdrawMsgState(ctx, req.PoolId, req.MsgIndex) + if !found { + return nil, status.Errorf(codes.NotFound, "the msg given msg_index %d doesn't exist or deleted", req.MsgIndex) + } + + return &types.QueryPoolBatchWithdrawMsgResponse{ + Withdraw: msg, + }, nil +} + +// PoolBatchWithdrawMsgs queries all pool batch withdraw messages of the liquidity pool. +func (k Querier) PoolBatchWithdrawMsgs(c context.Context, req *types.QueryPoolBatchWithdrawMsgsRequest) (*types.QueryPoolBatchWithdrawMsgsResponse, error) { + empty := &types.QueryPoolBatchWithdrawMsgsRequest{} + if req == nil || *req == *empty { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + _, found := k.GetPool(ctx, req.PoolId) + if !found { + return nil, status.Errorf(codes.NotFound, "liquidity pool %d doesn't exist", req.PoolId) + } + + store := ctx.KVStore(k.storeKey) + msgStore := prefix.NewStore(store, types.GetPoolBatchWithdrawMsgsPrefix(req.PoolId)) + var msgs []types.WithdrawMsgState + + pageRes, err := query.Paginate(msgStore, req.Pagination, func(key []byte, value []byte) error { + msg, err := types.UnmarshalWithdrawMsgState(k.cdc, value) + if err != nil { + return err + } + + msgs = append(msgs, msg) + + return nil + }) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.QueryPoolBatchWithdrawMsgsResponse{ + Withdraws: msgs, + Pagination: pageRes, + }, nil +} + +// Params queries params of liquidity module. +func (k Querier) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + params := k.GetParams(ctx) + + return &types.QueryParamsResponse{ + Params: params, + }, nil +} + +// MakeQueryLiquidityPoolResponse wraps MakeQueryLiquidityPoolResponse. +func (k Querier) MakeQueryLiquidityPoolResponse(pool types.Pool) (*types.QueryLiquidityPoolResponse, error) { + return &types.QueryLiquidityPoolResponse{ + Pool: pool, + }, nil +} + +// MakeQueryLiquidityPoolsResponse wraps a list of QueryLiquidityPoolResponses. +func (k Querier) MakeQueryLiquidityPoolsResponse(pools types.Pools) (*[]types.QueryLiquidityPoolResponse, error) { + resp := make([]types.QueryLiquidityPoolResponse, len(pools)) + for i, pool := range pools { + res := types.QueryLiquidityPoolResponse{ + Pool: pool, + } + resp[i] = res + } + return &resp, nil +} diff --git a/x/liquidity/keeper/grpc_query_test.go b/x/liquidity/keeper/grpc_query_test.go new file mode 100644 index 00000000000..9303bb28f9a --- /dev/null +++ b/x/liquidity/keeper/grpc_query_test.go @@ -0,0 +1,497 @@ +package keeper_test + +import ( + "context" + "fmt" + + "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func (suite *KeeperTestSuite) TestGRPCLiquidityPool() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + pool, found := app.LiquidityKeeper.GetPool(ctx, suite.pools[0].Id) + suite.True(found) + + var req *types.QueryLiquidityPoolRequest + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &types.QueryLiquidityPoolRequest{} + }, + false, + }, + { + "valid request", + func() { + req = &types.QueryLiquidityPoolRequest{PoolId: suite.pools[0].Id} + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.LiquidityPool(context.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.Equal(pool.Id, res.Pool.Id) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCLiquidityPoolByPoolCoinDenom() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + pool, found := app.LiquidityKeeper.GetPool(ctx, suite.pools[0].Id) + suite.True(found) + + var req *types.QueryLiquidityPoolByPoolCoinDenomRequest + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &types.QueryLiquidityPoolByPoolCoinDenomRequest{} + }, + false, + }, + { + "valid request", + func() { + req = &types.QueryLiquidityPoolByPoolCoinDenomRequest{PoolCoinDenom: suite.pools[0].PoolCoinDenom} + }, + true, + }, + { + "invalid request", + func() { + req = &types.QueryLiquidityPoolByPoolCoinDenomRequest{PoolCoinDenom: suite.pools[0].PoolCoinDenom[:10]} + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.LiquidityPoolByPoolCoinDenom(context.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.Equal(pool.Id, res.Pool.Id) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCLiquidityPoolByReserveAcc() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + pool, found := app.LiquidityKeeper.GetPool(ctx, suite.pools[0].Id) + suite.True(found) + + var req *types.QueryLiquidityPoolByReserveAccRequest + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &types.QueryLiquidityPoolByReserveAccRequest{} + }, + false, + }, + { + "valid request", + func() { + req = &types.QueryLiquidityPoolByReserveAccRequest{ReserveAcc: suite.pools[0].ReserveAccountAddress} + }, + true, + }, + { + "invalid request", + func() { + req = &types.QueryLiquidityPoolByReserveAccRequest{ReserveAcc: suite.pools[0].ReserveAccountAddress[:10]} + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.LiquidityPoolByReserveAcc(context.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.Equal(pool.Id, res.Pool.Id) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryLiquidityPools() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + pools := app.LiquidityKeeper.GetAllPools(ctx) + + var req *types.QueryLiquidityPoolsRequest + testCases := []struct { + msg string + malleate func() + expPass bool + numPools int + hasNext bool + }{ + { + "empty request", + func() { + req = &types.QueryLiquidityPoolsRequest{ + Pagination: &query.PageRequest{}, + } + }, + true, + 2, + false, + }, + { + "valid request", + func() { + req = &types.QueryLiquidityPoolsRequest{ + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + 1, + true, + }, + { + "valid request", + func() { + req = &types.QueryLiquidityPoolsRequest{ + Pagination: &query.PageRequest{Limit: 10, CountTotal: true}, + } + }, + true, + 2, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + resp, err := queryClient.LiquidityPools(context.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.NotNil(resp) + suite.Equal(tc.numPools, len(resp.Pools)) + suite.Equal(uint64(len(pools)), resp.Pagination.Total) + + if tc.hasNext { + suite.NotNil(resp.Pagination.NextKey) + } else { + suite.Nil(resp.Pagination.NextKey) + } + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCLiquidityPoolBatch() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + batch, found := app.LiquidityKeeper.GetPoolBatch(ctx, suite.pools[0].Id) + suite.True(found) + + var req *types.QueryLiquidityPoolBatchRequest + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &types.QueryLiquidityPoolBatchRequest{} + }, + false, + }, + { + "valid request", + func() { + req = &types.QueryLiquidityPoolBatchRequest{PoolId: suite.pools[0].Id} + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.LiquidityPoolBatch(context.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.True(batch.Equal(&res.Batch)) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryBatchDepositMsgs() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + msgs := app.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, suite.batches[0]) + + var req *types.QueryPoolBatchDepositMsgsRequest + testCases := []struct { + msg string + malleate func() + expPass bool + numMsgs int + hasNext bool + }{ + { + "empty request", + func() { + req = &types.QueryPoolBatchDepositMsgsRequest{} + }, + false, + 0, + false, + }, + { + "returns all the pool batch deposit Msgs", + func() { + req = &types.QueryPoolBatchDepositMsgsRequest{ + PoolId: suite.batches[0].PoolId, + } + }, + true, + len(msgs), + false, + }, + { + "valid request", + func() { + req = &types.QueryPoolBatchDepositMsgsRequest{ + PoolId: suite.batches[0].PoolId, + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + 1, + true, + }, + { + "valid request", + func() { + req = &types.QueryPoolBatchDepositMsgsRequest{ + PoolId: suite.batches[0].PoolId, + Pagination: &query.PageRequest{Limit: 10, CountTotal: true}, + } + }, + true, + len(msgs), + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + resp, err := queryClient.PoolBatchDepositMsgs(context.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.NotNil(resp) + suite.Equal(tc.numMsgs, len(resp.Deposits)) + suite.Equal(uint64(len(msgs)), resp.Pagination.Total) + + if tc.hasNext { + suite.NotNil(resp.Pagination.NextKey) + } else { + suite.Nil(resp.Pagination.NextKey) + } + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryBatchWithdrawMsgs() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + msgs := app.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, suite.batches[0]) + + var req *types.QueryPoolBatchWithdrawMsgsRequest + testCases := []struct { + msg string + malleate func() + expPass bool + numMsgs int + hasNext bool + }{ + { + "empty request", + func() { + req = &types.QueryPoolBatchWithdrawMsgsRequest{} + }, + false, + 0, + false, + }, + { + "returns all the pool batch withdraw Msgs", + func() { + req = &types.QueryPoolBatchWithdrawMsgsRequest{ + PoolId: suite.batches[0].PoolId, + } + }, + true, + len(msgs), + false, + }, + { + "valid request", + func() { + req = &types.QueryPoolBatchWithdrawMsgsRequest{ + PoolId: suite.batches[0].PoolId, + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + 1, + true, + }, + { + "valid request", + func() { + req = &types.QueryPoolBatchWithdrawMsgsRequest{ + PoolId: suite.batches[0].PoolId, + Pagination: &query.PageRequest{Limit: 10, CountTotal: true}, + } + }, + true, + len(msgs), + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + resp, err := queryClient.PoolBatchWithdrawMsgs(context.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.NotNil(resp) + suite.Equal(tc.numMsgs, len(resp.Withdraws)) + suite.Equal(uint64(len(msgs)), resp.Pagination.Total) + + if tc.hasNext { + suite.NotNil(resp.Pagination.NextKey) + } else { + suite.Nil(resp.Pagination.NextKey) + } + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryBatchSwapMsgs() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + msgs := app.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, suite.batches[0]) + + var req *types.QueryPoolBatchSwapMsgsRequest + testCases := []struct { + msg string + malleate func() + expPass bool + numMsgs int + hasNext bool + }{ + { + "empty request", + func() { + req = &types.QueryPoolBatchSwapMsgsRequest{} + }, + false, + 0, + false, + }, + { + "returns all the pool batch swap Msgs", + func() { + req = &types.QueryPoolBatchSwapMsgsRequest{ + PoolId: suite.batches[0].PoolId, + } + }, + true, + len(msgs), + false, + }, + { + "valid request", + func() { + req = &types.QueryPoolBatchSwapMsgsRequest{ + PoolId: suite.batches[0].PoolId, + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + 1, + true, + }, + { + "valid request", + func() { + req = &types.QueryPoolBatchSwapMsgsRequest{ + PoolId: suite.batches[0].PoolId, + Pagination: &query.PageRequest{Limit: 10, CountTotal: true}, + } + }, + true, + len(msgs), + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + resp, err := queryClient.PoolBatchSwapMsgs(context.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.NotNil(resp) + suite.Equal(tc.numMsgs, len(resp.Swaps)) + suite.Equal(uint64(len(msgs)), resp.Pagination.Total) + + if tc.hasNext { + suite.NotNil(resp.Pagination.NextKey) + } else { + suite.Nil(resp.Pagination.NextKey) + } + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/x/liquidity/keeper/invariants.go b/x/liquidity/keeper/invariants.go new file mode 100644 index 00000000000..251b6f15bf2 --- /dev/null +++ b/x/liquidity/keeper/invariants.go @@ -0,0 +1,378 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// RegisterInvariants registers all liquidity invariants. +func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { + ir.RegisterRoute(types.ModuleName, "escrow-amount", + LiquidityPoolsEscrowAmountInvariant(k)) +} + +// AllInvariants runs all invariants of the liquidity module. +func AllInvariants(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + res, stop := LiquidityPoolsEscrowAmountInvariant(k)(ctx) + return res, stop + } +} + +// LiquidityPoolsEscrowAmountInvariant checks that outstanding unwithdrawn fees are never negative. +func LiquidityPoolsEscrowAmountInvariant(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + remainingCoins := sdk.NewCoins() + batches := k.GetAllPoolBatches(ctx) + for _, batch := range batches { + swapMsgs := k.GetAllPoolBatchSwapMsgStatesNotToBeDeleted(ctx, batch) + for _, msg := range swapMsgs { + remainingCoins = remainingCoins.Add(msg.RemainingOfferCoin) + } + depositMsgs := k.GetAllPoolBatchDepositMsgStatesNotToBeDeleted(ctx, batch) + for _, msg := range depositMsgs { + remainingCoins = remainingCoins.Add(msg.Msg.DepositCoins...) + } + withdrawMsgs := k.GetAllPoolBatchWithdrawMsgStatesNotToBeDeleted(ctx, batch) + for _, msg := range withdrawMsgs { + remainingCoins = remainingCoins.Add(msg.Msg.PoolCoin) + } + } + + batchEscrowAcc := k.accountKeeper.GetModuleAddress(types.ModuleName) + escrowAmt := k.bankKeeper.GetAllBalances(ctx, batchEscrowAcc) + + broken := !escrowAmt.IsAllGTE(remainingCoins) + + return sdk.FormatInvariant(types.ModuleName, "batch escrow amount invariant broken", + "batch escrow amount LT batch remaining amount"), broken + } +} + +// These invariants cannot be registered via RegisterInvariants since the module uses per-block batch execution. +// We should approach adding these invariant checks inside actual logics of deposit / withdraw / swap. + +var ( + BatchLogicInvariantCheckFlag = false // It is only used at the development stage, and is disabled at the product level. + // For coin amounts less than coinAmountThreshold, a high errorRate does not mean + // that the calculation logic has errors. + // For example, if there were two X coins and three Y coins in the pool, and someone deposits + // one X coin and one Y coin, it's an acceptable input. + // But pool price would change from 2/3 to 3/4 so errorRate will report 1/8(=0.125), + // meaning that the price has changed by 12.5%. + // This happens with small coin amounts, so there should be a threshold for coin amounts + // before we calculate the errorRate. + errorRateThreshold = sdk.NewDecWithPrec(5, 2) // 5% + coinAmountThreshold = sdk.NewInt(20) // If a decimal error occurs at a value less than 20, the error rate is over 5%. +) + +func errorRate(expected, actual sdk.Dec) sdk.Dec { + // To prevent divide-by-zero panics, return 1.0(=100%) as the error rate + // when the expected value is 0. + if expected.IsZero() { + return sdk.OneDec() + } + return actual.Sub(expected).Quo(expected).Abs() +} + +// MintingPoolCoinsInvariant checks the correct ratio of minting amount of pool coins. +func MintingPoolCoinsInvariant(poolCoinTotalSupply, mintPoolCoin, depositCoinA, depositCoinB, lastReserveCoinA, lastReserveCoinB, refundedCoinA, refundedCoinB sdk.Int) { + if !refundedCoinA.IsZero() { + depositCoinA = depositCoinA.Sub(refundedCoinA) + } + + if !refundedCoinB.IsZero() { + depositCoinB = depositCoinB.Sub(refundedCoinB) + } + + poolCoinRatio := mintPoolCoin.ToDec().QuoInt(poolCoinTotalSupply) + depositCoinARatio := depositCoinA.ToDec().QuoInt(lastReserveCoinA) + depositCoinBRatio := depositCoinB.ToDec().QuoInt(lastReserveCoinB) + expectedMintPoolCoinAmtBasedA := depositCoinARatio.MulInt(poolCoinTotalSupply).TruncateInt() + expectedMintPoolCoinAmtBasedB := depositCoinBRatio.MulInt(poolCoinTotalSupply).TruncateInt() + + // NewPoolCoinAmount / LastPoolCoinSupply == AfterRefundedDepositCoinA / LastReserveCoinA + // NewPoolCoinAmount / LastPoolCoinSupply == AfterRefundedDepositCoinA / LastReserveCoinB + if depositCoinA.GTE(coinAmountThreshold) && depositCoinB.GTE(coinAmountThreshold) && + lastReserveCoinA.GTE(coinAmountThreshold) && lastReserveCoinB.GTE(coinAmountThreshold) && + mintPoolCoin.GTE(coinAmountThreshold) && poolCoinTotalSupply.GTE(coinAmountThreshold) { + if errorRate(depositCoinARatio, poolCoinRatio).GT(errorRateThreshold) || + errorRate(depositCoinBRatio, poolCoinRatio).GT(errorRateThreshold) { + panic("invariant check fails due to incorrect ratio of pool coins") + } + } + + if mintPoolCoin.GTE(coinAmountThreshold) && + (sdk.MaxInt(mintPoolCoin, expectedMintPoolCoinAmtBasedA).Sub(sdk.MinInt(mintPoolCoin, expectedMintPoolCoinAmtBasedA)).ToDec().QuoInt(mintPoolCoin).GT(errorRateThreshold) || + sdk.MaxInt(mintPoolCoin, expectedMintPoolCoinAmtBasedB).Sub(sdk.MinInt(mintPoolCoin, expectedMintPoolCoinAmtBasedA)).ToDec().QuoInt(mintPoolCoin).GT(errorRateThreshold)) { + panic("invariant check fails due to incorrect amount of pool coins") + } +} + +// DepositInvariant checks after deposit amounts. +func DepositInvariant(lastReserveCoinA, lastReserveCoinB, depositCoinA, depositCoinB, afterReserveCoinA, afterReserveCoinB, refundedCoinA, refundedCoinB sdk.Int) { + depositCoinA = depositCoinA.Sub(refundedCoinA) + depositCoinB = depositCoinB.Sub(refundedCoinB) + + depositCoinRatio := depositCoinA.ToDec().Quo(depositCoinB.ToDec()) + lastReserveRatio := lastReserveCoinA.ToDec().Quo(lastReserveCoinB.ToDec()) + afterReserveRatio := afterReserveCoinA.ToDec().Quo(afterReserveCoinB.ToDec()) + + // AfterDepositReserveCoinA = LastReserveCoinA + AfterRefundedDepositCoinA + // AfterDepositReserveCoinB = LastReserveCoinB + AfterRefundedDepositCoinA + if !afterReserveCoinA.Equal(lastReserveCoinA.Add(depositCoinA)) || + !afterReserveCoinB.Equal(lastReserveCoinB.Add(depositCoinB)) { + panic("invariant check fails due to incorrect deposit amounts") + } + + if depositCoinA.GTE(coinAmountThreshold) && depositCoinB.GTE(coinAmountThreshold) && + lastReserveCoinA.GTE(coinAmountThreshold) && lastReserveCoinB.GTE(coinAmountThreshold) { + // AfterRefundedDepositCoinA / AfterRefundedDepositCoinA = LastReserveCoinA / LastReserveCoinB + if errorRate(lastReserveRatio, depositCoinRatio).GT(errorRateThreshold) { + panic("invariant check fails due to incorrect deposit ratio") + } + // LastReserveCoinA / LastReserveCoinB = AfterDepositReserveCoinA / AfterDepositReserveCoinB + if errorRate(lastReserveRatio, afterReserveRatio).GT(errorRateThreshold) { + panic("invariant check fails due to incorrect pool price ratio") + } + } +} + +// BurningPoolCoinsInvariant checks the correct burning amount of pool coins. +func BurningPoolCoinsInvariant(burnedPoolCoin, withdrawCoinA, withdrawCoinB, reserveCoinA, reserveCoinB, lastPoolCoinSupply sdk.Int, withdrawFeeCoins sdk.Coins) { + burningPoolCoinRatio := burnedPoolCoin.ToDec().Quo(lastPoolCoinSupply.ToDec()) + if burningPoolCoinRatio.Equal(sdk.OneDec()) { + return + } + + withdrawCoinARatio := withdrawCoinA.Add(withdrawFeeCoins[0].Amount).ToDec().Quo(reserveCoinA.ToDec()) + withdrawCoinBRatio := withdrawCoinB.Add(withdrawFeeCoins[1].Amount).ToDec().Quo(reserveCoinB.ToDec()) + + // BurnedPoolCoinAmount / LastPoolCoinSupply >= (WithdrawCoinA+WithdrawFeeCoinA) / LastReserveCoinA + // BurnedPoolCoinAmount / LastPoolCoinSupply >= (WithdrawCoinB+WithdrawFeeCoinB) / LastReserveCoinB + if withdrawCoinARatio.GT(burningPoolCoinRatio) || withdrawCoinBRatio.GT(burningPoolCoinRatio) { + panic("invariant check fails due to incorrect ratio of burning pool coins") + } + + expectedBurningPoolCoinBasedA := lastPoolCoinSupply.ToDec().MulTruncate(withdrawCoinARatio).TruncateInt() + expectedBurningPoolCoinBasedB := lastPoolCoinSupply.ToDec().MulTruncate(withdrawCoinBRatio).TruncateInt() + + if burnedPoolCoin.GTE(coinAmountThreshold) && + (sdk.MaxInt(burnedPoolCoin, expectedBurningPoolCoinBasedA).Sub(sdk.MinInt(burnedPoolCoin, expectedBurningPoolCoinBasedA)).ToDec().QuoInt(burnedPoolCoin).GT(errorRateThreshold) || + sdk.MaxInt(burnedPoolCoin, expectedBurningPoolCoinBasedB).Sub(sdk.MinInt(burnedPoolCoin, expectedBurningPoolCoinBasedB)).ToDec().QuoInt(burnedPoolCoin).GT(errorRateThreshold)) { + panic("invariant check fails due to incorrect amount of burning pool coins") + } +} + +// WithdrawReserveCoinsInvariant checks the after withdraw amounts. +func WithdrawReserveCoinsInvariant(withdrawCoinA, withdrawCoinB, reserveCoinA, reserveCoinB, + afterReserveCoinA, afterReserveCoinB, afterPoolCoinTotalSupply, lastPoolCoinSupply, burnedPoolCoin sdk.Int, +) { + // AfterWithdrawReserveCoinA = LastReserveCoinA - WithdrawCoinA + if !afterReserveCoinA.Equal(reserveCoinA.Sub(withdrawCoinA)) { + panic("invariant check fails due to incorrect withdraw coin A amount") + } + + // AfterWithdrawReserveCoinB = LastReserveCoinB - WithdrawCoinB + if !afterReserveCoinB.Equal(reserveCoinB.Sub(withdrawCoinB)) { + panic("invariant check fails due to incorrect withdraw coin B amount") + } + + // AfterWithdrawPoolCoinSupply = LastPoolCoinSupply - BurnedPoolCoinAmount + if !afterPoolCoinTotalSupply.Equal(lastPoolCoinSupply.Sub(burnedPoolCoin)) { + panic("invariant check fails due to incorrect total supply") + } +} + +// WithdrawAmountInvariant checks the correct ratio of withdraw coin amounts. +func WithdrawAmountInvariant(withdrawCoinA, withdrawCoinB, reserveCoinA, reserveCoinB, burnedPoolCoin, poolCoinSupply sdk.Int, withdrawFeeRate sdk.Dec) { + ratio := burnedPoolCoin.ToDec().Quo(poolCoinSupply.ToDec()).Mul(sdk.OneDec().Sub(withdrawFeeRate)) + idealWithdrawCoinA := reserveCoinA.ToDec().Mul(ratio) + idealWithdrawCoinB := reserveCoinB.ToDec().Mul(ratio) + diffA := idealWithdrawCoinA.Sub(withdrawCoinA.ToDec()).Abs() + diffB := idealWithdrawCoinB.Sub(withdrawCoinB.ToDec()).Abs() + if !burnedPoolCoin.Equal(poolCoinSupply) { + if diffA.GTE(sdk.OneDec()) { + panic(fmt.Sprintf("withdraw coin amount %v differs too much from %v", withdrawCoinA, idealWithdrawCoinA)) + } + if diffB.GTE(sdk.OneDec()) { + panic(fmt.Sprintf("withdraw coin amount %v differs too much from %v", withdrawCoinB, idealWithdrawCoinB)) + } + } +} + +// ImmutablePoolPriceAfterWithdrawInvariant checks the immutable pool price after withdrawing coins. +func ImmutablePoolPriceAfterWithdrawInvariant(reserveCoinA, reserveCoinB, withdrawCoinA, withdrawCoinB, afterReserveCoinA, afterReserveCoinB sdk.Int) { + // TestReinitializePool tests a scenario where after reserve coins are zero + if !afterReserveCoinA.IsZero() && !afterReserveCoinB.IsZero() { + reserveCoinA = reserveCoinA.Sub(withdrawCoinA) + reserveCoinB = reserveCoinB.Sub(withdrawCoinB) + + reserveCoinRatio := reserveCoinA.ToDec().Quo(reserveCoinB.ToDec()) + afterReserveCoinRatio := afterReserveCoinA.ToDec().Quo(afterReserveCoinB.ToDec()) + + // LastReserveCoinA / LastReserveCoinB = AfterWithdrawReserveCoinA / AfterWithdrawReserveCoinB + if reserveCoinA.GTE(coinAmountThreshold) && reserveCoinB.GTE(coinAmountThreshold) && + withdrawCoinA.GTE(coinAmountThreshold) && withdrawCoinB.GTE(coinAmountThreshold) && + errorRate(reserveCoinRatio, afterReserveCoinRatio).GT(errorRateThreshold) { + panic("invariant check fails due to incorrect pool price ratio") + } + } +} + +// SwapMatchingInvariants checks swap matching results of both X to Y and Y to X cases. +func SwapMatchingInvariants(xToY, yToX []*types.SwapMsgState, matchResultXtoY, matchResultYtoX []types.MatchResult) { + beforeMatchingXtoYLen := len(xToY) + beforeMatchingYtoXLen := len(yToX) + afterMatchingXtoYLen := len(matchResultXtoY) + afterMatchingYtoXLen := len(matchResultYtoX) + + notMatchedXtoYLen := beforeMatchingXtoYLen - afterMatchingXtoYLen + notMatchedYtoXLen := beforeMatchingYtoXLen - afterMatchingYtoXLen + + if notMatchedXtoYLen != types.CountNotMatchedMsgs(xToY) { + panic("invariant check fails due to invalid xToY match length") + } + + if notMatchedYtoXLen != types.CountNotMatchedMsgs(yToX) { + panic("invariant check fails due to invalid yToX match length") + } +} + +// SwapPriceInvariants checks swap price invariants. +func SwapPriceInvariants(matchResultXtoY, matchResultYtoX []types.MatchResult, poolXDelta, poolYDelta, poolXDelta2, poolYDelta2 sdk.Dec, result types.BatchResult) { + invariantCheckX := sdk.ZeroDec() + invariantCheckY := sdk.ZeroDec() + + for _, m := range matchResultXtoY { + invariantCheckX = invariantCheckX.Sub(m.TransactedCoinAmt) + invariantCheckY = invariantCheckY.Add(m.ExchangedDemandCoinAmt) + } + + for _, m := range matchResultYtoX { + invariantCheckY = invariantCheckY.Sub(m.TransactedCoinAmt) + invariantCheckX = invariantCheckX.Add(m.ExchangedDemandCoinAmt) + } + + invariantCheckX = invariantCheckX.Add(poolXDelta2) + invariantCheckY = invariantCheckY.Add(poolYDelta2) + + if !invariantCheckX.IsZero() && !invariantCheckY.IsZero() { + panic(fmt.Errorf("invariant check fails due to invalid swap price: %s", invariantCheckX.String())) + } + + validitySwapPrice := types.CheckSwapPrice(matchResultXtoY, matchResultYtoX, result.SwapPrice) + if !validitySwapPrice { + panic("invariant check fails due to invalid swap price") + } +} + +// SwapPriceDirectionInvariants checks whether the calculated swap price is increased, decreased, or stayed from the last pool price. +func SwapPriceDirectionInvariants(currentPoolPrice sdk.Dec, batchResult types.BatchResult) { + switch batchResult.PriceDirection { + case types.Increasing: + if !batchResult.SwapPrice.GT(currentPoolPrice) { + panic("invariant check fails due to incorrect price direction") + } + case types.Decreasing: + if !batchResult.SwapPrice.LT(currentPoolPrice) { + panic("invariant check fails due to incorrect price direction") + } + case types.Staying: + if !batchResult.SwapPrice.Equal(currentPoolPrice) { + panic("invariant check fails due to incorrect price direction") + } + } +} + +// SwapMsgStatesInvariants checks swap match result states invariants. +func SwapMsgStatesInvariants(matchResultXtoY, matchResultYtoX []types.MatchResult, matchResultMap map[uint64]types.MatchResult, + swapMsgStates []*types.SwapMsgState, xToY, yToX []*types.SwapMsgState, +) { + if len(matchResultXtoY)+len(matchResultYtoX) != len(matchResultMap) { + panic("invalid length of match result") + } + + for k, v := range matchResultMap { + if k != v.SwapMsgState.MsgIndex { + panic("broken map consistency") + } + } + + for _, sms := range swapMsgStates { + for _, smsXtoY := range xToY { + if sms.MsgIndex == smsXtoY.MsgIndex { + if *(sms) != *(smsXtoY) || sms != smsXtoY { + panic("swap message state not matched") + } else { + break + } + } + } + + for _, smsYtoX := range yToX { + if sms.MsgIndex == smsYtoX.MsgIndex { + if *(sms) != *(smsYtoX) || sms != smsYtoX { + panic("swap message state not matched") + } else { + break + } + } + } + + if msgAfter, ok := matchResultMap[sms.MsgIndex]; ok { + if sms.MsgIndex == msgAfter.SwapMsgState.MsgIndex { + if *(sms) != *(msgAfter.SwapMsgState) || sms != msgAfter.SwapMsgState { + panic("batch message not matched") + } + } else { + panic("fail msg pointer consistency") + } + } + } +} + +// SwapOrdersExecutionStateInvariants checks all executed orders have order price which is not "executable" or not "unexecutable". +func SwapOrdersExecutionStateInvariants(matchResultMap map[uint64]types.MatchResult, swapMsgStates []*types.SwapMsgState, + batchResult types.BatchResult, denomX string, +) { + for _, sms := range swapMsgStates { + if _, ok := matchResultMap[sms.MsgIndex]; ok { + if !sms.Executed || !sms.Succeeded { + panic("swap msg state consistency error, matched but not succeeded") + } + + if sms.Msg.OfferCoin.Denom == denomX { + // buy orders having equal or higher order price than found swapPrice + if !sms.Msg.OrderPrice.GTE(batchResult.SwapPrice) { + panic("execution validity failed, executed but unexecutable") + } + } else { + // sell orders having equal or lower order price than found swapPrice + if !sms.Msg.OrderPrice.LTE(batchResult.SwapPrice) { + panic("execution validity failed, executed but unexecutable") + } + } + } else { + // check whether every unexecuted orders have order price which is not "executable" + if sms.Executed && sms.Succeeded { + panic("sms consistency error, not matched but succeeded") + } + + if sms.Msg.OfferCoin.Denom == denomX { + // buy orders having equal or lower order price than found swapPrice + if !sms.Msg.OrderPrice.LTE(batchResult.SwapPrice) { + panic("execution validity failed, unexecuted but executable") + } + } else { + // sell orders having equal or higher order price than found swapPrice + if !sms.Msg.OrderPrice.GTE(batchResult.SwapPrice) { + panic("execution validity failed, unexecuted but executable") + } + } + } + } +} diff --git a/x/liquidity/keeper/invariants_test.go b/x/liquidity/keeper/invariants_test.go new file mode 100644 index 00000000000..944e2d0ddd0 --- /dev/null +++ b/x/liquidity/keeper/invariants_test.go @@ -0,0 +1,144 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestWithdrawRatioInvariant(t *testing.T) { + require.NotPanics(t, func() { + keeper.WithdrawAmountInvariant(sdk.NewInt(1), sdk.NewInt(1), sdk.NewInt(2), sdk.NewInt(3), sdk.NewInt(1), sdk.NewInt(2), types.DefaultParams().WithdrawFeeRate) + }) + require.Panics(t, func() { + keeper.WithdrawAmountInvariant(sdk.NewInt(1), sdk.NewInt(1), sdk.NewInt(2), sdk.NewInt(5), sdk.NewInt(1), sdk.NewInt(2), types.DefaultParams().WithdrawFeeRate) + }) +} + +func TestMintingPoolCoinsInvariant(t *testing.T) { + for _, tc := range []struct { + poolCoinSupply int64 + mintingPoolCoin int64 + reserveA int64 + depositA int64 + refundedA int64 + reserveB int64 + depositB int64 + refundedB int64 + expectPanic bool + }{ + { + 10000, 1000, + 100000, 10000, 0, + 100000, 10000, 0, + false, + }, + { + 10000, 1000, + 100000, 10000, 5000, + 100000, 10000, 300, + true, + }, + { + 3000000, 100, + 100000000, 4000, 667, + 200000000, 8000, 1334, + false, + }, + { + 3000000, 100, + 100000000, 4000, 0, + 200000000, 8000, 1334, + true, + }, + } { + f := require.NotPanics + if tc.expectPanic { + f = require.Panics + } + f(t, func() { + keeper.MintingPoolCoinsInvariant( + sdk.NewInt(tc.poolCoinSupply), + sdk.NewInt(tc.mintingPoolCoin), + sdk.NewInt(tc.depositA), + sdk.NewInt(tc.depositB), + sdk.NewInt(tc.reserveA), + sdk.NewInt(tc.reserveB), + sdk.NewInt(tc.refundedA), + sdk.NewInt(tc.refundedB), + ) + }) + } +} + +func TestLiquidityPoolsEscrowAmountInvariant(t *testing.T) { + simapp, ctx := app.CreateTestInput() + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(1000000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + // begin block, init + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, true) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, true) + + invariant := keeper.AllInvariants(simapp.LiquidityKeeper) + _, broken := invariant(ctx) + require.False(t, broken) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + _, broken = invariant(ctx) + require.False(t, broken) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, broken = invariant(ctx) + require.False(t, broken) + + price, _ := sdk.NewDecFromStr("1.1") + priceY, _ := sdk.NewDecFromStr("1.2") + xOfferCoins := []sdk.Coin{sdk.NewCoin(denomX, sdk.NewInt(10000))} + yOfferCoins := []sdk.Coin{sdk.NewCoin(denomY, sdk.NewInt(5000))} + xOrderPrices := []sdk.Dec{price} + yOrderPrices := []sdk.Dec{priceY} + xOrderAddrs := addrs[1:2] + yOrderAddrs := addrs[2:3] + app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, yOfferCoins, yOrderPrices, yOrderAddrs, poolID, false) + + _, broken = invariant(ctx) + require.False(t, broken) + + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + _, broken = invariant(ctx) + require.False(t, broken) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, broken = invariant(ctx) + require.False(t, broken) + + batchEscrowAcc := simapp.AccountKeeper.GetModuleAddress(types.ModuleName) + escrowAmt := simapp.BankKeeper.GetAllBalances(ctx, batchEscrowAcc) + require.NotEmpty(t, escrowAmt) + err := simapp.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addrs[0], + sdk.NewCoins(sdk.NewCoin(xOfferCoins[0].Denom, xOfferCoins[0].Amount.QuoRaw(2)))) + require.NoError(t, err) + escrowAmt = simapp.BankKeeper.GetAllBalances(ctx, batchEscrowAcc) + + msg, broken := invariant(ctx) + require.True(t, broken) + require.Equal(t, "liquidity: batch escrow amount invariant broken invariant\nbatch escrow amount LT batch remaining amount\n", msg) +} diff --git a/x/liquidity/keeper/keeper.go b/x/liquidity/keeper/keeper.go new file mode 100644 index 00000000000..be05ad49a5b --- /dev/null +++ b/x/liquidity/keeper/keeper.go @@ -0,0 +1,69 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// Keeper of the liquidity store +type Keeper struct { + cdc codec.BinaryCodec + storeKey sdk.StoreKey + bankKeeper types.BankKeeper + accountKeeper types.AccountKeeper + distrKeeper types.DistributionKeeper + paramSpace paramstypes.Subspace +} + +// NewKeeper returns a liquidity keeper. It handles: +// - creating new ModuleAccounts for each pool ReserveAccount +// - sending to and from ModuleAccounts +// - minting, burning PoolCoins +func NewKeeper(cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramstypes.Subspace, bankKeeper types.BankKeeper, accountKeeper types.AccountKeeper, distrKeeper types.DistributionKeeper) Keeper { + // ensure liquidity module account is set + if addr := accountKeeper.GetModuleAddress(types.ModuleName); addr == nil { + panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) + } + + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + + return Keeper{ + storeKey: key, + bankKeeper: bankKeeper, + accountKeeper: accountKeeper, + distrKeeper: distrKeeper, + cdc: cdc, + paramSpace: paramSpace, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", types.ModuleName) +} + +// GetParams gets the parameters for the liquidity module. +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramSpace.GetParamSet(ctx, ¶ms) + return params +} + +// SetParams sets the parameters for the liquidity module. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} + +// GetCircuitBreakerEnabled returns circuit breaker enabled param from the paramspace. +func (k Keeper) GetCircuitBreakerEnabled(ctx sdk.Context) (enabled bool) { + k.paramSpace.Get(ctx, types.KeyCircuitBreakerEnabled, &enabled) + return +} diff --git a/x/liquidity/keeper/keeper_test.go b/x/liquidity/keeper/keeper_test.go new file mode 100644 index 00000000000..578a96b3f5d --- /dev/null +++ b/x/liquidity/keeper/keeper_test.go @@ -0,0 +1,64 @@ +package keeper_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + lapp "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +type KeeperTestSuite struct { + suite.Suite + + app *lapp.LiquidityApp + ctx sdk.Context + addrs []sdk.AccAddress + pools []types.Pool + batches []types.PoolBatch + depositMsgs []types.DepositMsgState + withdrawMsgs []types.WithdrawMsgState + swapMsgs []types.SwapMsgState + queryClient types.QueryClient +} + +func (suite *KeeperTestSuite) SetupTest() { + app, ctx := createTestInput() + + querier := keeper.Querier{Keeper: app.LiquidityKeeper} + + queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, querier) + + suite.addrs, suite.pools, suite.batches, suite.depositMsgs, suite.withdrawMsgs = createLiquidity(suite.T(), ctx, app) + + suite.ctx = ctx + suite.app = app + + // types.RegisterQueryServer(queryHelper, app.LiquidityKeeper) + suite.queryClient = types.NewQueryClient(queryHelper) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func TestCircuitBreakerEnabled(t *testing.T) { + app, ctx := createTestInput() + + enabled := app.LiquidityKeeper.GetCircuitBreakerEnabled(ctx) + require.Equal(t, false, enabled) + + params := app.LiquidityKeeper.GetParams(ctx) + params.CircuitBreakerEnabled = true + + app.LiquidityKeeper.SetParams(ctx, params) + + enabled = app.LiquidityKeeper.GetCircuitBreakerEnabled(ctx) + require.Equal(t, true, enabled) +} diff --git a/x/liquidity/keeper/liquidity_pool.go b/x/liquidity/keeper/liquidity_pool.go new file mode 100644 index 00000000000..4b092039333 --- /dev/null +++ b/x/liquidity/keeper/liquidity_pool.go @@ -0,0 +1,915 @@ +package keeper + +import ( + "fmt" + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func (k Keeper) ValidateMsgCreatePool(ctx sdk.Context, msg *types.MsgCreatePool) error { + params := k.GetParams(ctx) + var poolType types.PoolType + + // check poolType exist, get poolType from param + if len(params.PoolTypes) >= int(msg.PoolTypeId) { + poolType = params.PoolTypes[msg.PoolTypeId-1] + if poolType.Id != msg.PoolTypeId { + return types.ErrPoolTypeNotExists + } + } else { + return types.ErrPoolTypeNotExists + } + + reserveCoinNum := uint32(msg.DepositCoins.Len()) + if reserveCoinNum > poolType.MaxReserveCoinNum || poolType.MinReserveCoinNum > reserveCoinNum { + return types.ErrNumOfReserveCoin + } + + reserveCoinDenoms := make([]string, reserveCoinNum) + for i := 0; i < int(reserveCoinNum); i++ { + reserveCoinDenoms[i] = msg.DepositCoins.GetDenomByIndex(i) + } + + denomA, denomB := types.AlphabeticalDenomPair(reserveCoinDenoms[0], reserveCoinDenoms[1]) + if denomA != msg.DepositCoins[0].Denom || denomB != msg.DepositCoins[1].Denom { + return types.ErrBadOrderingReserveCoin + } + + if denomA == denomB { + return types.ErrEqualDenom + } + + if err := types.ValidateReserveCoinLimit(params.MaxReserveCoinAmount, msg.DepositCoins); err != nil { + return err + } + + poolName := types.PoolName(reserveCoinDenoms, msg.PoolTypeId) + reserveAcc := types.GetPoolReserveAcc(poolName, false) + _, found := k.GetPoolByReserveAccIndex(ctx, reserveAcc) + if found { + return types.ErrPoolAlreadyExists + } + return nil +} + +func (k Keeper) MintAndSendPoolCoin(ctx sdk.Context, pool types.Pool, srcAddr, creatorAddr sdk.AccAddress, depositCoins sdk.Coins) (sdk.Coin, error) { + cacheCtx, writeCache := ctx.CacheContext() + + params := k.GetParams(cacheCtx) + + mintingCoin := sdk.NewCoin(pool.PoolCoinDenom, params.InitPoolCoinMintAmount) + mintingCoins := sdk.NewCoins(mintingCoin) + if err := k.bankKeeper.MintCoins(cacheCtx, types.ModuleName, mintingCoins); err != nil { + return sdk.Coin{}, err + } + + reserveAcc := pool.GetReserveAccount() + + var inputs []banktypes.Input + var outputs []banktypes.Output + + inputs = append(inputs, banktypes.NewInput(srcAddr, depositCoins)) + outputs = append(outputs, banktypes.NewOutput(reserveAcc, depositCoins)) + + inputs = append(inputs, banktypes.NewInput(k.accountKeeper.GetModuleAddress(types.ModuleName), mintingCoins)) + outputs = append(outputs, banktypes.NewOutput(creatorAddr, mintingCoins)) + + if err := k.bankKeeper.InputOutputCoins(cacheCtx, inputs, outputs); err != nil { + return sdk.Coin{}, err + } + + writeCache() + + return mintingCoin, nil +} + +func (k Keeper) CreatePool(ctx sdk.Context, msg *types.MsgCreatePool) (types.Pool, error) { + if err := k.ValidateMsgCreatePool(ctx, msg); err != nil { + return types.Pool{}, err + } + + params := k.GetParams(ctx) + + denom1, denom2 := types.AlphabeticalDenomPair(msg.DepositCoins[0].Denom, msg.DepositCoins[1].Denom) + reserveCoinDenoms := []string{denom1, denom2} + + poolName := types.PoolName(reserveCoinDenoms, msg.PoolTypeId) + + pool := types.Pool{ + // Id: will set on SetPoolAtomic + TypeId: msg.PoolTypeId, + ReserveCoinDenoms: reserveCoinDenoms, + ReserveAccountAddress: types.GetPoolReserveAcc(poolName, false).String(), + PoolCoinDenom: types.GetPoolCoinDenom(poolName), + } + + poolCreator := msg.GetPoolCreator() + + for _, coin := range msg.DepositCoins { + if coin.Amount.LT(params.MinInitDepositAmount) { + return types.Pool{}, sdkerrors.Wrapf( + types.ErrLessThanMinInitDeposit, "deposit coin %s is smaller than %s", coin, params.MinInitDepositAmount) + } + } + + for _, coin := range msg.DepositCoins { + balance := k.bankKeeper.GetBalance(ctx, poolCreator, coin.Denom) + if balance.IsLT(coin) { + return types.Pool{}, sdkerrors.Wrapf( + types.ErrInsufficientBalance, "%s is smaller than %s", balance, coin) + } + } + + for _, coin := range params.PoolCreationFee { + balance := k.bankKeeper.GetBalance(ctx, poolCreator, coin.Denom) + neededAmt := coin.Amount.Add(msg.DepositCoins.AmountOf(coin.Denom)) + neededCoin := sdk.NewCoin(coin.Denom, neededAmt) + if balance.IsLT(neededCoin) { + return types.Pool{}, sdkerrors.Wrapf( + types.ErrInsufficientPoolCreationFee, "%s is smaller than %s", balance, neededCoin) + } + } + + if _, err := k.MintAndSendPoolCoin(ctx, pool, poolCreator, poolCreator, msg.DepositCoins); err != nil { + return types.Pool{}, err + } + + // pool creation fees are collected in community pool + if err := k.distrKeeper.FundCommunityPool(ctx, params.PoolCreationFee, poolCreator); err != nil { + return types.Pool{}, err + } + + pool = k.SetPoolAtomic(ctx, pool) + batch := types.NewPoolBatch(pool.Id, 1) + batch.BeginHeight = ctx.BlockHeight() + + k.SetPoolBatch(ctx, batch) + + reserveCoins := k.GetReserveCoins(ctx, pool) + lastReserveRatio := sdk.NewDecFromInt(reserveCoins[0].Amount).Quo(sdk.NewDecFromInt(reserveCoins[1].Amount)) + logger := k.Logger(ctx) + logger.Debug( + "create liquidity pool", + "msg", msg, + "pool", pool, + "reserveCoins", reserveCoins, + "lastReserveRatio", lastReserveRatio, + ) + + return pool, nil +} + +func (k Keeper) ExecuteDeposit(ctx sdk.Context, msg types.DepositMsgState, batch types.PoolBatch) error { + if msg.Executed || msg.ToBeDeleted || msg.Succeeded { + return fmt.Errorf("cannot process already executed batch msg") + } + msg.Executed = true + k.SetPoolBatchDepositMsgState(ctx, msg.Msg.PoolId, msg) + + if err := k.ValidateMsgDepositWithinBatch(ctx, *msg.Msg); err != nil { + return err + } + + pool, found := k.GetPool(ctx, msg.Msg.PoolId) + if !found { + return types.ErrPoolNotExists + } + + depositCoins := msg.Msg.DepositCoins.Sort() + + batchEscrowAcc := k.accountKeeper.GetModuleAddress(types.ModuleName) + reserveAcc := pool.GetReserveAccount() + depositor := msg.Msg.GetDepositor() + + params := k.GetParams(ctx) + + reserveCoins := k.GetReserveCoins(ctx, pool) + + // reinitialize pool if the pool is depleted + if k.IsDepletedPool(ctx, pool) { + for _, depositCoin := range msg.Msg.DepositCoins { + if depositCoin.Amount.Add(reserveCoins.AmountOf(depositCoin.Denom)).LT(params.MinInitDepositAmount) { + return types.ErrLessThanMinInitDeposit + } + } + poolCoin, err := k.MintAndSendPoolCoin(ctx, pool, batchEscrowAcc, depositor, msg.Msg.DepositCoins) + if err != nil { + return err + } + + // set deposit msg state of the pool batch complete + msg.Succeeded = true + msg.ToBeDeleted = true + k.SetPoolBatchDepositMsgState(ctx, msg.Msg.PoolId, msg) + + reserveCoins = k.GetReserveCoins(ctx, pool) + lastReserveCoinA := sdk.NewDecFromInt(reserveCoins[0].Amount) + lastReserveCoinB := sdk.NewDecFromInt(reserveCoins[1].Amount) + lastReserveRatio := lastReserveCoinA.Quo(lastReserveCoinB) + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeDepositToPool, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(batch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(msg.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueDepositor, depositor.String()), + sdk.NewAttribute(types.AttributeValueAcceptedCoins, msg.Msg.DepositCoins.String()), + sdk.NewAttribute(types.AttributeValueRefundedCoins, ""), + sdk.NewAttribute(types.AttributeValuePoolCoinDenom, poolCoin.Denom), + sdk.NewAttribute(types.AttributeValuePoolCoinAmount, poolCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueSuccess, types.Success), + ), + ) + logger := k.Logger(ctx) + logger.Debug( + "reinitialize pool", + "msg", msg, + "pool", pool, + "reserveCoins", reserveCoins, + "lastReserveRatio", lastReserveRatio, + ) + + return nil + } + + reserveCoins.Sort() + + lastReserveCoinA := reserveCoins[0] + lastReserveCoinB := reserveCoins[1] + + depositCoinA := depositCoins[0] + depositCoinB := depositCoins[1] + + poolCoinTotalSupply := k.GetPoolCoinTotalSupply(ctx, pool).ToDec() + if err := types.CheckOverflowWithDec(poolCoinTotalSupply, depositCoinA.Amount.ToDec()); err != nil { + return err + } + if err := types.CheckOverflowWithDec(poolCoinTotalSupply, depositCoinB.Amount.ToDec()); err != nil { + return err + } + poolCoinMintAmt := sdk.MinDec( + poolCoinTotalSupply.MulTruncate(depositCoinA.Amount.ToDec()).QuoTruncate(lastReserveCoinA.Amount.ToDec()), + poolCoinTotalSupply.MulTruncate(depositCoinB.Amount.ToDec()).QuoTruncate(lastReserveCoinB.Amount.ToDec()), + ) + mintRate := poolCoinMintAmt.TruncateDec().QuoTruncate(poolCoinTotalSupply) + acceptedCoins := sdk.NewCoins( + sdk.NewCoin(depositCoins[0].Denom, lastReserveCoinA.Amount.ToDec().Mul(mintRate).TruncateInt()), + sdk.NewCoin(depositCoins[1].Denom, lastReserveCoinB.Amount.ToDec().Mul(mintRate).TruncateInt()), + ) + refundedCoins := depositCoins.Sub(acceptedCoins) + refundedCoinA := sdk.NewCoin(depositCoinA.Denom, refundedCoins.AmountOf(depositCoinA.Denom)) + refundedCoinB := sdk.NewCoin(depositCoinB.Denom, refundedCoins.AmountOf(depositCoinB.Denom)) + + mintPoolCoin := sdk.NewCoin(pool.PoolCoinDenom, poolCoinMintAmt.TruncateInt()) + mintPoolCoins := sdk.NewCoins(mintPoolCoin) + + if mintPoolCoins.IsZero() || acceptedCoins.IsZero() { + return fmt.Errorf("pool coin truncated, no accepted coin, refund") + } + + if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, mintPoolCoins); err != nil { + return err + } + + var inputs []banktypes.Input + var outputs []banktypes.Output + + if !refundedCoins.IsZero() { + // refund truncated deposit coins + inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, refundedCoins)) + outputs = append(outputs, banktypes.NewOutput(depositor, refundedCoins)) + } + + // send accepted deposit coins + inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, acceptedCoins)) + outputs = append(outputs, banktypes.NewOutput(reserveAcc, acceptedCoins)) + + // send minted pool coins + inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, mintPoolCoins)) + outputs = append(outputs, banktypes.NewOutput(depositor, mintPoolCoins)) + + // execute multi-send + if err := k.bankKeeper.InputOutputCoins(ctx, inputs, outputs); err != nil { + return err + } + + msg.Succeeded = true + msg.ToBeDeleted = true + k.SetPoolBatchDepositMsgState(ctx, msg.Msg.PoolId, msg) + + if BatchLogicInvariantCheckFlag { + afterReserveCoins := k.GetReserveCoins(ctx, pool) + afterReserveCoinA := afterReserveCoins[0].Amount + afterReserveCoinB := afterReserveCoins[1].Amount + + MintingPoolCoinsInvariant(poolCoinTotalSupply.TruncateInt(), mintPoolCoin.Amount, depositCoinA.Amount, depositCoinB.Amount, + lastReserveCoinA.Amount, lastReserveCoinB.Amount, refundedCoinA.Amount, refundedCoinB.Amount) + DepositInvariant(lastReserveCoinA.Amount, lastReserveCoinB.Amount, depositCoinA.Amount, depositCoinB.Amount, + afterReserveCoinA, afterReserveCoinB, refundedCoinA.Amount, refundedCoinB.Amount) + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeDepositToPool, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(batch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(msg.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueDepositor, depositor.String()), + sdk.NewAttribute(types.AttributeValueAcceptedCoins, acceptedCoins.String()), + sdk.NewAttribute(types.AttributeValueRefundedCoins, refundedCoins.String()), + sdk.NewAttribute(types.AttributeValuePoolCoinDenom, mintPoolCoin.Denom), + sdk.NewAttribute(types.AttributeValuePoolCoinAmount, mintPoolCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueSuccess, types.Success), + ), + ) + + reserveCoins = k.GetReserveCoins(ctx, pool) + lastReserveRatio := sdk.NewDecFromInt(reserveCoins[0].Amount).Quo(sdk.NewDecFromInt(reserveCoins[1].Amount)) + + logger := k.Logger(ctx) + logger.Debug( + "deposit coins to the pool", + "msg", msg, + "pool", pool, + "inputs", inputs, + "outputs", outputs, + "reserveCoins", reserveCoins, + "lastReserveRatio", lastReserveRatio, + ) + + return nil +} + +// ExecuteWithdrawal withdraws pool coin from the liquidity pool +func (k Keeper) ExecuteWithdrawal(ctx sdk.Context, msg types.WithdrawMsgState, batch types.PoolBatch) error { + if msg.Executed || msg.ToBeDeleted || msg.Succeeded { + return fmt.Errorf("cannot process already executed batch msg") + } + msg.Executed = true + k.SetPoolBatchWithdrawMsgState(ctx, msg.Msg.PoolId, msg) + + if err := k.ValidateMsgWithdrawWithinBatch(ctx, *msg.Msg); err != nil { + return err + } + poolCoins := sdk.NewCoins(msg.Msg.PoolCoin) + + pool, found := k.GetPool(ctx, msg.Msg.PoolId) + if !found { + return types.ErrPoolNotExists + } + + poolCoinTotalSupply := k.GetPoolCoinTotalSupply(ctx, pool) + reserveCoins := k.GetReserveCoins(ctx, pool) + reserveCoins.Sort() + + var inputs []banktypes.Input + var outputs []banktypes.Output + + reserveAcc := pool.GetReserveAccount() + withdrawer := msg.Msg.GetWithdrawer() + + params := k.GetParams(ctx) + withdrawProportion := sdk.OneDec().Sub(params.WithdrawFeeRate) + withdrawCoins := sdk.NewCoins() + withdrawFeeCoins := sdk.NewCoins() + + // Case for withdrawing all reserve coins + if msg.Msg.PoolCoin.Amount.Equal(poolCoinTotalSupply) { + withdrawCoins = reserveCoins + } else { + // Calculate withdraw amount of respective reserve coin considering fees and pool coin's totally supply + for _, reserveCoin := range reserveCoins { + if err := types.CheckOverflow(reserveCoin.Amount, msg.Msg.PoolCoin.Amount); err != nil { + return err + } + if err := types.CheckOverflow(reserveCoin.Amount.Mul(msg.Msg.PoolCoin.Amount).ToDec().TruncateInt(), poolCoinTotalSupply); err != nil { + return err + } + // WithdrawAmount = ReserveAmount * PoolCoinAmount * WithdrawFeeProportion / TotalSupply + withdrawAmtWithFee := reserveCoin.Amount.Mul(msg.Msg.PoolCoin.Amount).ToDec().TruncateInt().Quo(poolCoinTotalSupply) + withdrawAmt := reserveCoin.Amount.Mul(msg.Msg.PoolCoin.Amount).ToDec().MulTruncate(withdrawProportion).TruncateInt().Quo(poolCoinTotalSupply) + withdrawCoins = append(withdrawCoins, sdk.NewCoin(reserveCoin.Denom, withdrawAmt)) + withdrawFeeCoins = append(withdrawFeeCoins, sdk.NewCoin(reserveCoin.Denom, withdrawAmtWithFee.Sub(withdrawAmt))) + } + } + + if withdrawCoins.IsValid() { + inputs = append(inputs, banktypes.NewInput(reserveAcc, withdrawCoins)) + outputs = append(outputs, banktypes.NewOutput(withdrawer, withdrawCoins)) + } else { + return types.ErrBadPoolCoinAmount + } + + // send withdrawing coins to the withdrawer + if err := k.bankKeeper.InputOutputCoins(ctx, inputs, outputs); err != nil { + return err + } + + // burn the escrowed pool coins + if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, poolCoins); err != nil { + return err + } + + msg.Succeeded = true + msg.ToBeDeleted = true + k.SetPoolBatchWithdrawMsgState(ctx, msg.Msg.PoolId, msg) + + if BatchLogicInvariantCheckFlag { + afterPoolCoinTotalSupply := k.GetPoolCoinTotalSupply(ctx, pool) + afterReserveCoins := k.GetReserveCoins(ctx, pool) + afterReserveCoinA := sdk.ZeroInt() + afterReserveCoinB := sdk.ZeroInt() + if !afterReserveCoins.IsZero() { + afterReserveCoinA = afterReserveCoins[0].Amount + afterReserveCoinB = afterReserveCoins[1].Amount + } + burnedPoolCoin := poolCoins[0].Amount + withdrawCoinA := withdrawCoins[0].Amount + withdrawCoinB := withdrawCoins[1].Amount + reserveCoinA := reserveCoins[0].Amount + reserveCoinB := reserveCoins[1].Amount + lastPoolCoinTotalSupply := poolCoinTotalSupply + afterPoolTotalSupply := afterPoolCoinTotalSupply + + BurningPoolCoinsInvariant(burnedPoolCoin, withdrawCoinA, withdrawCoinB, reserveCoinA, reserveCoinB, lastPoolCoinTotalSupply, withdrawFeeCoins) + WithdrawReserveCoinsInvariant(withdrawCoinA, withdrawCoinB, reserveCoinA, reserveCoinB, + afterReserveCoinA, afterReserveCoinB, afterPoolTotalSupply, lastPoolCoinTotalSupply, burnedPoolCoin) + WithdrawAmountInvariant(withdrawCoinA, withdrawCoinB, reserveCoinA, reserveCoinB, burnedPoolCoin, lastPoolCoinTotalSupply, params.WithdrawFeeRate) + ImmutablePoolPriceAfterWithdrawInvariant(reserveCoinA, reserveCoinB, withdrawCoinA, withdrawCoinB, afterReserveCoinA, afterReserveCoinB) + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeWithdrawFromPool, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(batch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(msg.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueWithdrawer, withdrawer.String()), + sdk.NewAttribute(types.AttributeValuePoolCoinDenom, msg.Msg.PoolCoin.Denom), + sdk.NewAttribute(types.AttributeValuePoolCoinAmount, msg.Msg.PoolCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueWithdrawCoins, withdrawCoins.String()), + sdk.NewAttribute(types.AttributeValueWithdrawFeeCoins, withdrawFeeCoins.String()), + sdk.NewAttribute(types.AttributeValueSuccess, types.Success), + ), + ) + + reserveCoins = k.GetReserveCoins(ctx, pool) + + var lastReserveRatio sdk.Dec + if reserveCoins.IsZero() { + lastReserveRatio = sdk.ZeroDec() + } else { + lastReserveRatio = sdk.NewDecFromInt(reserveCoins[0].Amount).Quo(sdk.NewDecFromInt(reserveCoins[1].Amount)) + } + + logger := k.Logger(ctx) + logger.Debug( + "withdraw pool coin from the pool", + "msg", msg, + "pool", pool, + "inputs", inputs, + "outputs", outputs, + "reserveCoins", reserveCoins, + "lastReserveRatio", lastReserveRatio, + ) + + return nil +} + +// GetPoolCoinTotalSupply returns total supply of pool coin of the pool in form of sdk.Int +func (k Keeper) GetPoolCoinTotalSupply(ctx sdk.Context, pool types.Pool) sdk.Int { + return k.bankKeeper.GetSupply(ctx, pool.PoolCoinDenom).Amount +} + +// IsDepletedPool returns true if the pool is depleted. +func (k Keeper) IsDepletedPool(ctx sdk.Context, pool types.Pool) bool { + reserveCoins := k.GetReserveCoins(ctx, pool) + return !k.GetPoolCoinTotalSupply(ctx, pool).IsPositive() || + reserveCoins.AmountOf(pool.ReserveCoinDenoms[0]).IsZero() || + reserveCoins.AmountOf(pool.ReserveCoinDenoms[1]).IsZero() +} + +// GetPoolCoinTotal returns total supply of pool coin of the pool in form of sdk.Coin +func (k Keeper) GetPoolCoinTotal(ctx sdk.Context, pool types.Pool) sdk.Coin { + return sdk.NewCoin(pool.PoolCoinDenom, k.GetPoolCoinTotalSupply(ctx, pool)) +} + +// GetReserveCoins returns reserve coins from the liquidity pool +func (k Keeper) GetReserveCoins(ctx sdk.Context, pool types.Pool) (reserveCoins sdk.Coins) { + reserveAcc := pool.GetReserveAccount() + reserveCoins = sdk.NewCoins() + for _, denom := range pool.ReserveCoinDenoms { + reserveCoins = append(reserveCoins, k.bankKeeper.GetBalance(ctx, reserveAcc, denom)) + } + return +} + +// GetPoolMetaData returns metadata of the pool +func (k Keeper) GetPoolMetaData(ctx sdk.Context, pool types.Pool) types.PoolMetadata { + return types.PoolMetadata{ + PoolId: pool.Id, + PoolCoinTotalSupply: k.GetPoolCoinTotal(ctx, pool), + ReserveCoins: k.GetReserveCoins(ctx, pool), + } +} + +// GetPoolRecord returns the liquidity pool record with the given pool information +func (k Keeper) GetPoolRecord(ctx sdk.Context, pool types.Pool) (types.PoolRecord, bool) { + batch, found := k.GetPoolBatch(ctx, pool.Id) + if !found { + return types.PoolRecord{}, false + } + return types.PoolRecord{ + Pool: pool, + PoolMetadata: k.GetPoolMetaData(ctx, pool), + PoolBatch: batch, + DepositMsgStates: k.GetAllPoolBatchDepositMsgs(ctx, batch), + WithdrawMsgStates: k.GetAllPoolBatchWithdrawMsgStates(ctx, batch), + SwapMsgStates: k.GetAllPoolBatchSwapMsgStates(ctx, batch), + }, true +} + +// SetPoolRecord stores liquidity pool states +func (k Keeper) SetPoolRecord(ctx sdk.Context, record types.PoolRecord) types.PoolRecord { + k.SetPoolAtomic(ctx, record.Pool) + if record.PoolBatch.BeginHeight > ctx.BlockHeight() { + record.PoolBatch.BeginHeight = 0 + } + k.SetPoolBatch(ctx, record.PoolBatch) + k.SetPoolBatchDepositMsgStates(ctx, record.Pool.Id, record.DepositMsgStates) + k.SetPoolBatchWithdrawMsgStates(ctx, record.Pool.Id, record.WithdrawMsgStates) + k.SetPoolBatchSwapMsgStates(ctx, record.Pool.Id, record.SwapMsgStates) + return record +} + +// RefundDeposit refunds deposit amounts to the depositor +func (k Keeper) RefundDeposit(ctx sdk.Context, batchMsg types.DepositMsgState, batch types.PoolBatch) error { + batchMsg, _ = k.GetPoolBatchDepositMsgState(ctx, batchMsg.Msg.PoolId, batchMsg.MsgIndex) + if !batchMsg.Executed || batchMsg.Succeeded { + return fmt.Errorf("cannot refund not executed or already succeeded msg") + } + pool, _ := k.GetPool(ctx, batchMsg.Msg.PoolId) + if err := k.ReleaseEscrow(ctx, batchMsg.Msg.GetDepositor(), batchMsg.Msg.DepositCoins); err != nil { + return err + } + // not delete now, set ToBeDeleted true for delete on next block beginblock + batchMsg.ToBeDeleted = true + k.SetPoolBatchDepositMsgState(ctx, batchMsg.Msg.PoolId, batchMsg) + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeDepositToPool, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(batch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(batchMsg.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueDepositor, batchMsg.Msg.GetDepositor().String()), + sdk.NewAttribute(types.AttributeValueAcceptedCoins, sdk.NewCoins().String()), + sdk.NewAttribute(types.AttributeValueRefundedCoins, batchMsg.Msg.DepositCoins.String()), + sdk.NewAttribute(types.AttributeValueSuccess, types.Failure), + )) + return nil +} + +// RefundWithdrawal refunds pool coin of the liquidity pool to the withdrawer +func (k Keeper) RefundWithdrawal(ctx sdk.Context, batchMsg types.WithdrawMsgState, batch types.PoolBatch) error { + batchMsg, _ = k.GetPoolBatchWithdrawMsgState(ctx, batchMsg.Msg.PoolId, batchMsg.MsgIndex) + if !batchMsg.Executed || batchMsg.Succeeded { + return fmt.Errorf("cannot refund not executed or already succeeded msg") + } + pool, _ := k.GetPool(ctx, batchMsg.Msg.PoolId) + if err := k.ReleaseEscrow(ctx, batchMsg.Msg.GetWithdrawer(), sdk.NewCoins(batchMsg.Msg.PoolCoin)); err != nil { + return err + } + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeWithdrawFromPool, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(batch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(batchMsg.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueWithdrawer, batchMsg.Msg.GetWithdrawer().String()), + sdk.NewAttribute(types.AttributeValuePoolCoinDenom, batchMsg.Msg.PoolCoin.Denom), + sdk.NewAttribute(types.AttributeValuePoolCoinAmount, batchMsg.Msg.PoolCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueSuccess, types.Failure), + )) + + // not delete now, set ToBeDeleted true for delete on next block beginblock + batchMsg.ToBeDeleted = true + k.SetPoolBatchWithdrawMsgState(ctx, batchMsg.Msg.PoolId, batchMsg) + return nil +} + +// TransactAndRefundSwapLiquidityPool transacts, refunds, expires, sends coins with escrow, update state by TransactAndRefundSwapLiquidityPool +func (k Keeper) TransactAndRefundSwapLiquidityPool(ctx sdk.Context, swapMsgStates []*types.SwapMsgState, + matchResultMap map[uint64]types.MatchResult, pool types.Pool, batchResult types.BatchResult, +) error { + var inputs []banktypes.Input + var outputs []banktypes.Output + batchEscrowAcc := k.accountKeeper.GetModuleAddress(types.ModuleName) + poolReserveAcc := pool.GetReserveAccount() + batch, found := k.GetPoolBatch(ctx, pool.Id) + if !found { + return types.ErrPoolBatchNotExists + } + sendCoin := func(from, to sdk.AccAddress, coin sdk.Coin) { + coins := sdk.NewCoins(coin) + if !coins.Empty() && coins.IsValid() { + inputs = append(inputs, banktypes.NewInput(from, coins)) + outputs = append(outputs, banktypes.NewOutput(to, coins)) + } + } + for _, sms := range swapMsgStates { + if pool.Id != sms.Msg.PoolId { + return fmt.Errorf("broken msg pool consistency") + } + if !sms.Executed && sms.Succeeded { + return fmt.Errorf("can't refund not executed with succeed msg") + } + if sms.RemainingOfferCoin.IsNegative() { + return fmt.Errorf("negative RemainingOfferCoin") + } else if sms.RemainingOfferCoin.IsPositive() && + ((!sms.ToBeDeleted && sms.OrderExpiryHeight <= ctx.BlockHeight()) || + (sms.ToBeDeleted && sms.OrderExpiryHeight != ctx.BlockHeight())) { + return fmt.Errorf("consistency of OrderExpiryHeight and ToBeDeleted flag is broken") + } + + if match, ok := matchResultMap[sms.MsgIndex]; ok { + transactedAmt := match.TransactedCoinAmt.TruncateInt() + receiveAmt := match.ExchangedDemandCoinAmt.Sub(match.ExchangedCoinFeeAmt).TruncateInt() + offerCoinFeeAmt := match.OfferCoinFeeAmt.TruncateInt() + + sendCoin(batchEscrowAcc, poolReserveAcc, sdk.NewCoin(sms.Msg.OfferCoin.Denom, transactedAmt)) + sendCoin(poolReserveAcc, sms.Msg.GetSwapRequester(), sdk.NewCoin(sms.Msg.DemandCoinDenom, receiveAmt)) + sendCoin(batchEscrowAcc, poolReserveAcc, sdk.NewCoin(sms.Msg.OfferCoin.Denom, offerCoinFeeAmt)) + + if sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee).IsPositive() && sms.OrderExpiryHeight == ctx.BlockHeight() { + sendCoin(batchEscrowAcc, sms.Msg.GetSwapRequester(), sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee)) + } + + sms.Succeeded = true + if sms.RemainingOfferCoin.IsZero() { + sms.ToBeDeleted = true + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeSwapTransacted, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(batch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(sms.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueSwapRequester, sms.Msg.GetSwapRequester().String()), + sdk.NewAttribute(types.AttributeValueSwapTypeId, strconv.FormatUint(uint64(sms.Msg.SwapTypeId), 10)), + sdk.NewAttribute(types.AttributeValueOfferCoinDenom, sms.Msg.OfferCoin.Denom), + sdk.NewAttribute(types.AttributeValueOfferCoinAmount, sms.Msg.OfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueDemandCoinDenom, sms.Msg.DemandCoinDenom), + sdk.NewAttribute(types.AttributeValueOrderPrice, sms.Msg.OrderPrice.String()), + sdk.NewAttribute(types.AttributeValueSwapPrice, batchResult.SwapPrice.String()), + sdk.NewAttribute(types.AttributeValueTransactedCoinAmount, transactedAmt.String()), + sdk.NewAttribute(types.AttributeValueRemainingOfferCoinAmount, sms.RemainingOfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueExchangedOfferCoinAmount, sms.ExchangedOfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueExchangedDemandCoinAmount, receiveAmt.String()), + sdk.NewAttribute(types.AttributeValueOfferCoinFeeAmount, offerCoinFeeAmt.String()), + sdk.NewAttribute(types.AttributeValueExchangedCoinFeeAmount, match.ExchangedCoinFeeAmt.String()), + sdk.NewAttribute(types.AttributeValueReservedOfferCoinFeeAmount, sms.ReservedOfferCoinFee.Amount.String()), + sdk.NewAttribute(types.AttributeValueOrderExpiryHeight, strconv.FormatInt(sms.OrderExpiryHeight, 10)), + sdk.NewAttribute(types.AttributeValueSuccess, types.Success), + )) + } else { + // Not matched, remaining + sendCoin(batchEscrowAcc, sms.Msg.GetSwapRequester(), sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee)) + sms.Succeeded = false + sms.ToBeDeleted = true + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeSwapTransacted, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(batch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(sms.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueSwapRequester, sms.Msg.GetSwapRequester().String()), + sdk.NewAttribute(types.AttributeValueSwapTypeId, strconv.FormatUint(uint64(sms.Msg.SwapTypeId), 10)), + sdk.NewAttribute(types.AttributeValueOfferCoinDenom, sms.Msg.OfferCoin.Denom), + sdk.NewAttribute(types.AttributeValueOfferCoinAmount, sms.Msg.OfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueDemandCoinDenom, sms.Msg.DemandCoinDenom), + sdk.NewAttribute(types.AttributeValueOrderPrice, sms.Msg.OrderPrice.String()), + sdk.NewAttribute(types.AttributeValueSwapPrice, batchResult.SwapPrice.String()), + sdk.NewAttribute(types.AttributeValueRemainingOfferCoinAmount, sms.RemainingOfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueExchangedOfferCoinAmount, sms.ExchangedOfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueReservedOfferCoinFeeAmount, sms.ReservedOfferCoinFee.Amount.String()), + sdk.NewAttribute(types.AttributeValueOrderExpiryHeight, strconv.FormatInt(sms.OrderExpiryHeight, 10)), + sdk.NewAttribute(types.AttributeValueSuccess, types.Failure), + )) + + } + } + if err := k.bankKeeper.InputOutputCoins(ctx, inputs, outputs); err != nil { + return err + } + k.SetPoolBatchSwapMsgStatesByPointer(ctx, pool.Id, swapMsgStates) + return nil +} + +func (k Keeper) RefundSwaps(ctx sdk.Context, pool types.Pool, swapMsgStates []*types.SwapMsgState) error { + var inputs []banktypes.Input + var outputs []banktypes.Output + sendCoin := func(from, to sdk.AccAddress, coin sdk.Coin) { + coins := sdk.NewCoins(coin) + if !coins.Empty() && coins.IsValid() { + inputs = append(inputs, banktypes.NewInput(from, coins)) + outputs = append(outputs, banktypes.NewOutput(to, coins)) + } + } + for _, sms := range swapMsgStates { + if sms.OrderExpiryHeight == ctx.BlockHeight() { + sendCoin(k.accountKeeper.GetModuleAddress(types.ModuleName), sms.Msg.GetSwapRequester(), sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee)) + sms.Succeeded = false + sms.ToBeDeleted = true + } + } + if err := k.bankKeeper.InputOutputCoins(ctx, inputs, outputs); err != nil { + return err + } + k.SetPoolBatchSwapMsgStatesByPointer(ctx, pool.Id, swapMsgStates) + return nil +} + +// ValidateMsgDepositWithinBatch validates MsgDepositWithinBatch +func (k Keeper) ValidateMsgDepositWithinBatch(ctx sdk.Context, msg types.MsgDepositWithinBatch) error { + pool, found := k.GetPool(ctx, msg.PoolId) + if !found { + return types.ErrPoolNotExists + } + + if msg.DepositCoins.Len() != len(pool.ReserveCoinDenoms) { + return types.ErrNumOfReserveCoin + } + + params := k.GetParams(ctx) + reserveCoins := k.GetReserveCoins(ctx, pool) + if err := types.ValidateReserveCoinLimit(params.MaxReserveCoinAmount, reserveCoins.Add(msg.DepositCoins...)); err != nil { + return err + } + + denomA, denomB := types.AlphabeticalDenomPair(msg.DepositCoins[0].Denom, msg.DepositCoins[1].Denom) + if denomA != pool.ReserveCoinDenoms[0] || denomB != pool.ReserveCoinDenoms[1] { + return types.ErrNotMatchedReserveCoin + } + return nil +} + +// ValidateMsgWithdrawWithinBatch validates MsgWithdrawWithinBatch +func (k Keeper) ValidateMsgWithdrawWithinBatch(ctx sdk.Context, msg types.MsgWithdrawWithinBatch) error { + pool, found := k.GetPool(ctx, msg.PoolId) + if !found { + return types.ErrPoolNotExists + } + + if msg.PoolCoin.Denom != pool.PoolCoinDenom { + return types.ErrBadPoolCoinDenom + } + + poolCoinTotalSupply := k.GetPoolCoinTotalSupply(ctx, pool) + if k.IsDepletedPool(ctx, pool) { + return types.ErrDepletedPool + } + + if msg.PoolCoin.Amount.GT(poolCoinTotalSupply) { + return types.ErrBadPoolCoinAmount + } + return nil +} + +// ValidateMsgSwapWithinBatch validates MsgSwapWithinBatch. +func (k Keeper) ValidateMsgSwapWithinBatch(ctx sdk.Context, msg types.MsgSwapWithinBatch, pool types.Pool) error { + denomA, denomB := types.AlphabeticalDenomPair(msg.OfferCoin.Denom, msg.DemandCoinDenom) + if denomA != pool.ReserveCoinDenoms[0] || denomB != pool.ReserveCoinDenoms[1] { + return types.ErrNotMatchedReserveCoin + } + + params := k.GetParams(ctx) + + // can not exceed max order ratio of reserve coins that can be ordered at a order + reserveCoinAmt := k.GetReserveCoins(ctx, pool).AmountOf(msg.OfferCoin.Denom) + + // Decimal Error, Multiply the Int coin amount by the Decimal Rate and erase the decimal point to order a lower value + maximumOrderableAmt := reserveCoinAmt.ToDec().MulTruncate(params.MaxOrderAmountRatio).TruncateInt() + if msg.OfferCoin.Amount.GT(maximumOrderableAmt) { + return types.ErrExceededMaxOrderable + } + + if msg.OfferCoinFee.Denom != msg.OfferCoin.Denom { + return types.ErrBadOfferCoinFee + } + + if err := types.CheckOverflowWithDec(msg.OfferCoin.Amount.ToDec(), msg.OrderPrice); err != nil { + return err + } + + if !msg.OfferCoinFee.Equal(types.GetOfferCoinFee(msg.OfferCoin, params.SwapFeeRate)) { + return types.ErrBadOfferCoinFee + } + + return nil +} + +// ValidatePool validates logic for liquidity pool after set or before export +func (k Keeper) ValidatePool(ctx sdk.Context, pool *types.Pool) error { + params := k.GetParams(ctx) + var poolType types.PoolType + + // check poolType exist, get poolType from param + if len(params.PoolTypes) >= int(pool.TypeId) { + poolType = params.PoolTypes[pool.TypeId-1] + if poolType.Id != pool.TypeId { + return types.ErrPoolTypeNotExists + } + } else { + return types.ErrPoolTypeNotExists + } + + if poolType.MaxReserveCoinNum > types.MaxReserveCoinNum || types.MinReserveCoinNum > poolType.MinReserveCoinNum { + return types.ErrNumOfReserveCoin + } + + reserveCoins := k.GetReserveCoins(ctx, *pool) + if uint32(reserveCoins.Len()) > poolType.MaxReserveCoinNum || poolType.MinReserveCoinNum > uint32(reserveCoins.Len()) { + return types.ErrNumOfReserveCoin + } + + if len(pool.ReserveCoinDenoms) != reserveCoins.Len() { + return types.ErrNumOfReserveCoin + } + for i, denom := range pool.ReserveCoinDenoms { + if denom != reserveCoins[i].Denom { + return types.ErrInvalidDenom + } + } + + denomA, denomB := types.AlphabeticalDenomPair(pool.ReserveCoinDenoms[0], pool.ReserveCoinDenoms[1]) + if denomA != pool.ReserveCoinDenoms[0] || denomB != pool.ReserveCoinDenoms[1] { + return types.ErrBadOrderingReserveCoin + } + + poolName := types.PoolName(pool.ReserveCoinDenoms, pool.TypeId) + poolCoin := k.GetPoolCoinTotal(ctx, *pool) + if poolCoin.Denom != types.GetPoolCoinDenom(poolName) { + return types.ErrBadPoolCoinDenom + } + + _, found := k.GetPoolBatch(ctx, pool.Id) + if !found { + return types.ErrPoolBatchNotExists + } + + return nil +} + +// ValidatePoolMetadata validates logic for liquidity pool metadata +func (k Keeper) ValidatePoolMetadata(ctx sdk.Context, pool *types.Pool, metaData *types.PoolMetadata) error { + if err := metaData.ReserveCoins.Validate(); err != nil { + return err + } + if !metaData.ReserveCoins.IsEqual(k.GetReserveCoins(ctx, *pool)) { + return types.ErrNumOfReserveCoin + } + if !metaData.PoolCoinTotalSupply.IsEqual(sdk.NewCoin(pool.PoolCoinDenom, k.GetPoolCoinTotalSupply(ctx, *pool))) { + return types.ErrBadPoolCoinAmount + } + return nil +} + +// ValidatePoolRecord validates liquidity pool record after init or after export +func (k Keeper) ValidatePoolRecord(ctx sdk.Context, record types.PoolRecord) error { + if err := k.ValidatePool(ctx, &record.Pool); err != nil { + return err + } + + if err := k.ValidatePoolMetadata(ctx, &record.Pool, &record.PoolMetadata); err != nil { + return err + } + + if len(record.DepositMsgStates) != 0 && record.PoolBatch.DepositMsgIndex != record.DepositMsgStates[len(record.DepositMsgStates)-1].MsgIndex+1 { + return types.ErrBadBatchMsgIndex + } + if len(record.WithdrawMsgStates) != 0 && record.PoolBatch.WithdrawMsgIndex != record.WithdrawMsgStates[len(record.WithdrawMsgStates)-1].MsgIndex+1 { + return types.ErrBadBatchMsgIndex + } + if len(record.SwapMsgStates) != 0 && record.PoolBatch.SwapMsgIndex != record.SwapMsgStates[len(record.SwapMsgStates)-1].MsgIndex+1 { + return types.ErrBadBatchMsgIndex + } + + return nil +} + +// IsPoolCoinDenom returns true if the denom is a valid pool coin denom. +func (k Keeper) IsPoolCoinDenom(ctx sdk.Context, denom string) bool { + reserveAcc, err := types.GetReserveAcc(denom, false) + if err != nil { + return false + } + _, found := k.GetPoolByReserveAccIndex(ctx, reserveAcc) + return found +} diff --git a/x/liquidity/keeper/liquidity_pool_test.go b/x/liquidity/keeper/liquidity_pool_test.go new file mode 100644 index 00000000000..ee51b56396c --- /dev/null +++ b/x/liquidity/keeper/liquidity_pool_test.go @@ -0,0 +1,1324 @@ +package keeper_test + +import ( + "fmt" + "math/rand" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestLiquidityPool(t *testing.T) { + app, ctx := createTestInput() + lp := types.Pool{ + Id: 0, + TypeId: 0, + ReserveCoinDenoms: []string{"a", "b"}, + ReserveAccountAddress: "", + PoolCoinDenom: "poolCoin", + } + app.LiquidityKeeper.SetPool(ctx, lp) + + lpGet, found := app.LiquidityKeeper.GetPool(ctx, 0) + require.True(t, found) + require.Equal(t, lp, lpGet) +} + +func TestCreatePool(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + invalidMsg := types.NewMsgCreatePool(addrs[0], 2, depositBalance) + _, err = simapp.LiquidityKeeper.CreatePool(ctx, invalidMsg) + require.ErrorIs(t, err, types.ErrPoolTypeNotExists) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + require.Equal(t, 1, len(pools)) + require.Equal(t, uint64(1), pools[0].Id) + require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1) + require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1]) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.ErrorIs(t, err, types.ErrPoolAlreadyExists) +} + +func TestCreatePoolInsufficientAmount(t *testing.T) { + simapp, ctx := createTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + depositCoins := sdk.NewCoins(sdk.NewInt64Coin(DenomX, 1000), sdk.NewInt64Coin(DenomY, 1000)) + creator := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) + + // Depositing coins that are less than params.MinInitDepositAmount. + _, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creator, types.DefaultPoolTypeID, depositCoins)) + require.ErrorIs(t, err, types.ErrLessThanMinInitDeposit) + + fakeDepositCoins := depositCoins.Add( + sdk.NewCoin(DenomX, params.MinInitDepositAmount), + sdk.NewCoin(DenomY, params.MinInitDepositAmount), + ) + // Depositing coins that are greater than the depositor has. + _, err = simapp.LiquidityKeeper.CreatePool( + ctx, types.NewMsgCreatePool(creator, types.DefaultPoolTypeID, fakeDepositCoins), + ) + require.ErrorIs(t, err, types.ErrInsufficientBalance) +} + +func TestPoolCreationFee(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + // Set PoolCreationFee for fail (insufficient balances for pool creation fee) + params.PoolCreationFee = depositBalance + simapp.LiquidityKeeper.SetParams(ctx, params) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.ErrorIs(t, types.ErrInsufficientPoolCreationFee, err) + + // Set PoolCreationFee for success + params.PoolCreationFee = types.DefaultPoolCreationFee + simapp.LiquidityKeeper.SetParams(ctx, params) + feePoolAcc := simapp.AccountKeeper.GetModuleAddress(distrtypes.ModuleName) + feePoolBalance := simapp.BankKeeper.GetAllBalances(ctx, feePoolAcc) + msg = types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + // Verify PoolCreationFee pay successfully + feePoolBalance = feePoolBalance.Add(params.PoolCreationFee...) + require.Equal(t, params.PoolCreationFee, feePoolBalance) + require.Equal(t, feePoolBalance, simapp.BankKeeper.GetAllBalances(ctx, feePoolAcc)) +} + +func TestExecuteDeposit(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 4, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + app.SaveAccount(simapp, ctx, addrs[1], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + depositA = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA) + depositB = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB) + depositBalance = sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + + depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + depositorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) + require.Equal(t, poolCoin.Sub(poolCoinBefore), depositorBalance.Amount) +} + +func TestExecuteDepositTruncation(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 4, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + initDeposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(10000000*1000000)), sdk.NewCoin(denomB, sdk.NewInt(200000000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], initDeposit) + app.SaveAccount(simapp, ctx, addrs[1], initDeposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, initDeposit, depositBalance) + + depositA = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA) + depositB = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB) + depositBalance = sdk.NewCoins(depositA, depositB) + + require.Equal(t, initDeposit, depositBalance) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(19*1000000)), sdk.NewCoin(denomB, sdk.NewInt(400*1000000))) + depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + depositorBalancePoolCoin := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) + depositorBalanceDenomA := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA) + depositorBalanceDenomB := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB) + require.Equal(t, depositBalance.AmountOf(denomA).Sub(sdk.NewInt(10*1000000)), depositorBalanceDenomA.Amount) + require.Equal(t, depositBalance.AmountOf(denomB).Sub(sdk.NewInt(200*1000000)), depositorBalanceDenomB.Amount) + require.Equal(t, depositorBalancePoolCoin.Amount, sdk.OneInt()) + require.Equal(t, poolCoin.Sub(poolCoinBefore), depositorBalancePoolCoin.Amount) +} + +func TestDepositDecimalTruncation(t *testing.T) { + simapp, ctx := createTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + params.WithdrawFeeRate = sdk.ZeroDec() + + // Suppose that atom price is $40. + denomA := "uatom" + denomB := "uusd" + + addrs := app.AddTestAddrs(simapp, ctx, 2, sdk.NewCoins()) + creator, depositor := addrs[0], addrs[1] + + // Create a pool with initial value of $10M. + depositCoins := sdk.NewCoins(sdk.NewInt64Coin(denomA, 125000*1000000), sdk.NewInt64Coin(denomB, 5000000*1000000)) + err := app.FundAccount(simapp, ctx, creator, depositCoins.Add(params.PoolCreationFee...)) + require.NoError(t, err) + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creator, types.DefaultPoolTypeID, depositCoins)) + require.NoError(t, err) + + // Deposit 19$. + depositCoins = sdk.NewCoins(sdk.NewInt64Coin(denomA, 0.2375*1000000), sdk.NewInt64Coin(denomB, 9.5*1000000)) + err = app.FundAccount(simapp, ctx, depositor, depositCoins) + require.NoError(t, err) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(depositor, pool.Id, depositCoins)) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + depositMsgStates := simapp.LiquidityKeeper.GetAllDepositMsgStates(ctx) + require.Len(t, depositMsgStates, 0) + + depositorPoolCoin := simapp.BankKeeper.GetBalance(ctx, depositor, pool.PoolCoinDenom) + require.True(sdk.IntEq(t, sdk.OneInt(), depositorPoolCoin.Amount)) + require.True(t, simapp.BankKeeper.GetBalance(ctx, depositor, denomA).Amount.IsPositive()) + require.True(t, simapp.BankKeeper.GetBalance(ctx, depositor, denomB).Amount.IsPositive()) + + // Withdraw. + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(depositor, pool.Id, depositorPoolCoin)) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + withdrawMsgStates := simapp.LiquidityKeeper.GetAllWithdrawMsgStates(ctx) + require.Len(t, withdrawMsgStates, 0) + + depositorCoinsDelta := depositCoins.Sub(simapp.BankKeeper.GetAllBalances(ctx, depositor)) + require.True(t, depositorCoinsDelta.IsZero()) +} + +func TestDepositDecimalTruncation2(t *testing.T) { + simapp, ctx := createTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + params.WithdrawFeeRate = sdk.ZeroDec() + + // Suppose that atom price is $40. + denomA := "uatom" + denomB := "uusd" + + addrs := app.AddTestAddrs(simapp, ctx, 2, sdk.NewCoins()) + creator, depositor := addrs[0], addrs[1] + + // Create a pool with initial value of $10M. + depositCoins := sdk.NewCoins(sdk.NewInt64Coin(denomA, 125000*1000000), sdk.NewInt64Coin(denomB, 5000000*1000000)) + err := app.FundAccount(simapp, ctx, creator, depositCoins.Add(params.PoolCreationFee...)) + require.NoError(t, err) + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creator, types.DefaultPoolTypeID, depositCoins)) + require.NoError(t, err) + + // Deposit 9$. + depositCoins = sdk.NewCoins(sdk.NewInt64Coin(denomA, 0.1125*1000000), sdk.NewInt64Coin(denomB, 4.5*1000000)) + err = app.FundAccount(simapp, ctx, depositor, depositCoins) + require.NoError(t, err) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(depositor, pool.Id, depositCoins)) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + depositorPoolCoin := simapp.BankKeeper.GetBalance(ctx, depositor, pool.PoolCoinDenom) + require.True(sdk.IntEq(t, sdk.ZeroInt(), depositorPoolCoin.Amount)) + require.True(t, simapp.BankKeeper.GetAllBalances(ctx, depositor).IsEqual(depositCoins)) + depositMsgStates := simapp.LiquidityKeeper.GetAllDepositMsgStates(ctx) + require.Len(t, depositMsgStates, 1) + require.True(t, depositMsgStates[0].Executed) + require.False(t, depositMsgStates[0].Succeeded) + require.True(t, depositMsgStates[0].ToBeDeleted) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + depositMsgStates = simapp.LiquidityKeeper.GetAllDepositMsgStates(ctx) + require.Len(t, depositMsgStates, 0) +} + +func TestReserveCoinLimit(t *testing.T) { + simapp, ctx := createTestInput() + params := types.DefaultParams() + params.MaxReserveCoinAmount = sdk.NewInt(1000000000000) + simapp.LiquidityKeeper.SetParams(ctx, params) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, params.MaxReserveCoinAmount), sdk.NewCoin(denomB, sdk.NewInt(1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + require.Equal(t, deposit, depositBalance) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.Equal(t, types.ErrExceededReserveCoinLimit, err) + + params.MaxReserveCoinAmount = sdk.ZeroInt() + simapp.LiquidityKeeper.SetParams(ctx, params) + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + params.MaxReserveCoinAmount = sdk.NewInt(1000000000000) + simapp.LiquidityKeeper.SetParams(ctx, params) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + deposit = sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(1000000)), sdk.NewCoin(denomB, sdk.NewInt(1000000))) + app.SaveAccount(simapp, ctx, addrs[1], deposit) + depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.Equal(t, types.ErrExceededReserveCoinLimit, err) + + params.MaxReserveCoinAmount = sdk.ZeroInt() + simapp.LiquidityKeeper.SetParams(ctx, params) + + depositMsg = types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + simapp.LiquidityKeeper.ExecutePoolBatches(ctx) + require.NoError(t, err) + + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + simapp.LiquidityKeeper.DeleteAndInitPoolBatches(ctx) + app.SaveAccount(simapp, ctx, addrs[1], deposit) + depositMsg = types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + params.MaxReserveCoinAmount = sdk.NewInt(1000000000000) + simapp.LiquidityKeeper.SetParams(ctx, params) + + poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + msgs = simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) + require.Equal(t, types.ErrExceededReserveCoinLimit, err) +} + +func TestExecuteWithdrawal(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + // Case for normal withdrawing + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) + withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, withdrawerPoolCoinBefore.Amount.QuoRaw(2))) + + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + require.Equal(t, poolCoinAfter, poolCoinBefore.QuoRaw(2)) + require.Equal(t, withdrawerPoolCoinAfter.Amount, withdrawerPoolCoinBefore.Amount.QuoRaw(2)) + withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) + withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]).QuoRaw(2).ToDec().Mul(sdk.OneDec().Sub(params.WithdrawFeeRate)).TruncateInt(), withdrawerDenomABalance.Amount) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]).QuoRaw(2).ToDec().Mul(sdk.OneDec().Sub(params.WithdrawFeeRate)).TruncateInt(), withdrawerDenomBBalance.Amount) + + // Case for withdrawing all reserve coins + poolCoinBefore = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinBefore = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) + withdrawMsg = types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) + + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + require.NoError(t, err) + + poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) + require.True(t, found) + msgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoinAfter = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinAfter = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + require.True(t, true, poolCoinAfter.IsZero()) + require.True(t, true, withdrawerPoolCoinAfter.IsZero()) + withdrawerDenomABalance = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) + withdrawerDenomBBalance = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]), withdrawerDenomABalance.Amount) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), withdrawerDenomBBalance.Amount) +} + +func TestSmallWithdrawalCase(t *testing.T) { + simapp, ctx := createTestInput() + params := types.DefaultParams() + params.InitPoolCoinMintAmount = sdk.NewInt(1_000000_000000) + simapp.LiquidityKeeper.SetParams(ctx, params) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(1250001*1000000)), sdk.NewCoin(denomB, sdk.NewInt(9*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + // Case for normal withdrawing + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + withdrawerDenomABalanceBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) + withdrawerDenomBBalanceBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) + + require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) + withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, sdk.NewInt(1))) + + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + require.Equal(t, poolCoinAfter, poolCoinBefore) + require.Equal(t, withdrawerPoolCoinAfter.Amount, withdrawerPoolCoinBefore.Amount) + withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) + withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) + + reservePoolBalanceA := simapp.BankKeeper.GetBalance(ctx, pool.GetReserveAccount(), pool.ReserveCoinDenoms[0]) + reservePoolBalanceB := simapp.BankKeeper.GetBalance(ctx, pool.GetReserveAccount(), pool.ReserveCoinDenoms[1]) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]), reservePoolBalanceA.Amount) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), reservePoolBalanceB.Amount) + require.Equal(t, withdrawerDenomABalanceBefore, withdrawerDenomABalance) + require.Equal(t, withdrawerDenomBBalanceBefore, withdrawerDenomBBalance) +} + +func TestReinitializePool(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + params.WithdrawFeeRate = sdk.ZeroDec() + simapp.LiquidityKeeper.SetParams(ctx, params) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(100*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + reserveCoins := simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.True(t, reserveCoins.IsEqual(deposit)) + + require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) + withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) + + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.True(t, true, poolCoinAfter.IsZero()) + require.True(t, true, withdrawerPoolCoinAfter.IsZero()) + withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) + withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]), withdrawerDenomABalance.Amount) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), withdrawerDenomBBalance.Amount) + + reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.True(t, reserveCoins.IsZero()) + + // error when swap request to depleted pool + offerCoin := sdk.NewCoin(denomA, withdrawerDenomABalance.Amount.QuoRaw(2)) + swapMsg := types.NewMsgSwapWithinBatch(addrs[0], pool.Id, types.DefaultSwapTypeID, offerCoin, denomB, sdk.MustNewDecFromStr("0.1"), params.SwapFeeRate) + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, swapMsg, 0) + require.ErrorIs(t, err, types.ErrDepletedPool) + + depositMsg := types.NewMsgDepositWithinBatch(addrs[0], pool.Id, deposit) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + depositMsgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 1, len(depositMsgs)) + + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, depositMsgs[0], poolBatch) + require.NoError(t, err) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + depositorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.Equal(t, poolCoin, depositorBalance.Amount) + + reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.True(t, reserveCoins.IsEqual(deposit)) +} + +func TestReserveAccManipulation(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + + // depositor, withdrawer + app.SaveAccount(simapp, ctx, addrs[0], deposit) + // reserveAccount manipulator + app.SaveAccount(simapp, ctx, addrs[1], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + // reserveAcc manipulation coinA + manipulationReserveA1 := sdk.NewCoin(denomA, sdk.NewInt(30*1000000)) + manipulationReserveA2 := sdk.NewCoin(denomA, sdk.NewInt(70*1000000)) + // reserveAcc manipulation coin other than reserve coins + manipulationReserveOther := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100*1000000)) + // manipulated reserve coinA + addedDepositA := depositA.Add(manipulationReserveA1).Add(manipulationReserveA2) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + reserveAcc := pool.GetReserveAccount() + reserveAccBalances := simapp.BankKeeper.GetAllBalances(ctx, reserveAcc) + require.Equal(t, reserveAccBalances, sdk.NewCoins(depositA, depositB)) + + // send coin to manipulate reserve account + simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA1)) + metadata := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pool) + require.Equal(t, depositA.Add(manipulationReserveA1).Amount, metadata.ReserveCoins.AmountOf(denomA)) + + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, withdrawerPoolCoinBefore.Amount.QuoRaw(2))) + simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + + poolBatch, _ := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // send coin to manipulate reserve account + simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA2)) + simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveOther)) + reserveAccBalances = simapp.BankKeeper.GetAllBalances(ctx, reserveAcc) + metadata = simapp.LiquidityKeeper.GetPoolMetaData(ctx, pool) + require.NotEqual(t, manipulationReserveOther, metadata.ReserveCoins.AmountOf(sdk.DefaultBondDenom)) + + // Case for withdrawing all reserve coins after manipulation + poolCoinBefore = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinBefore = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + withdrawMsg = types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) + + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + require.NoError(t, err) + + poolBatch, _ = simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) + msgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + + err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) + withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) + withdrawerDenomOtherBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], sdk.DefaultBondDenom) + require.Equal(t, addedDepositA, withdrawerDenomABalance) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), withdrawerDenomBBalance.Amount) + require.NotEqual(t, manipulationReserveOther, withdrawerDenomOtherBalance) +} + +func TestGetLiquidityPoolMetadata(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + require.Equal(t, 1, len(pools)) + require.Equal(t, uint64(1), pools[0].Id) + require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1) + require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1]) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.ErrorIs(t, err, types.ErrPoolAlreadyExists) + + metaData := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pools[0]) + require.Equal(t, pools[0].Id, metaData.PoolId) + + reserveCoin := simapp.LiquidityKeeper.GetReserveCoins(ctx, pools[0]) + require.Equal(t, reserveCoin, metaData.ReserveCoins) + require.Equal(t, msg.DepositCoins, metaData.ReserveCoins) + + totalSupply := sdk.NewCoin(pools[0].PoolCoinDenom, simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0])) + require.Equal(t, totalSupply, metaData.PoolCoinTotalSupply) + require.Equal(t, creatorBalance, metaData.PoolCoinTotalSupply) +} + +func TestIsPoolCoinDenom(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "denomA" + denomB := "denomB" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + getPool, found := simapp.LiquidityKeeper.GetPool(ctx, pool.Id) + require.True(t, found) + require.Equal(t, pool, getPool) + + require.Equal(t, "denomA/denomB/1", pool.Name()) + poolCoinDenom := types.GetPoolCoinDenom(pool.Name()) + require.Equal(t, pool.PoolCoinDenom, poolCoinDenom) + require.True(t, simapp.LiquidityKeeper.IsPoolCoinDenom(ctx, pool.PoolCoinDenom)) + require.False(t, simapp.LiquidityKeeper.IsPoolCoinDenom(ctx, pool.Name())) +} + +func TestGetPoolByReserveAccIndex(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + fmt.Println(pool) + poolStored, found := simapp.LiquidityKeeper.GetPool(ctx, pool.Id) + require.True(t, found) + require.Equal(t, pool, poolStored) + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + require.Equal(t, pool, pools[0]) + + poolByReserveAcc, found := simapp.LiquidityKeeper.GetPoolByReserveAccIndex(ctx, pool.GetReserveAccount()) + require.True(t, found) + require.Equal(t, pool, poolByReserveAcc) + + poolCoinDenom := types.GetPoolCoinDenom(pool.Name()) + require.Equal(t, pool.PoolCoinDenom, poolCoinDenom) + require.True(t, simapp.LiquidityKeeper.IsPoolCoinDenom(ctx, pool.PoolCoinDenom)) + require.False(t, simapp.LiquidityKeeper.IsPoolCoinDenom(ctx, pool.Name())) + // SetPoolByReserveAccIndex +} + +func TestDepositWithdrawEdgecase(t *testing.T) { + for seed := int64(0); seed < 20; seed++ { + r := rand.New(rand.NewSource(seed)) + + simapp, ctx := createTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + X := params.MinInitDepositAmount.Add(app.GetRandRange(r, 0, 1_000_000)) + Y := params.MinInitDepositAmount.Add(app.GetRandRange(r, 0, 1_000_000)) + + creatorCoins := sdk.NewCoins(sdk.NewCoin(DenomX, X), sdk.NewCoin(DenomY, Y)) + creatorAddr := app.AddRandomTestAddr(simapp, ctx, creatorCoins.Add(params.PoolCreationFee...)) + + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creatorAddr, types.DefaultPoolTypeID, creatorCoins)) + require.NoError(t, err) + + for i := 0; i < 500; i++ { + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + type action int + const ( + deposit action = iota + 1 + withdraw + ) + actions := []action{} + balanceX := simapp.BankKeeper.GetBalance(ctx, creatorAddr, DenomX) + balanceY := simapp.BankKeeper.GetBalance(ctx, creatorAddr, DenomY) + balancePoolCoin := simapp.BankKeeper.GetBalance(ctx, creatorAddr, pool.PoolCoinDenom) + if balanceX.IsPositive() || balanceY.IsPositive() { + actions = append(actions, deposit) + } + if balancePoolCoin.Amount.GT(sdk.OneInt()) { + actions = append(actions, withdraw) + } + require.Positive(t, len(actions)) + switch actions[r.Intn(len(actions))] { + case deposit: + depositAmtA := sdk.OneInt().Add(sdk.NewInt(r.Int63n(balanceX.Amount.Int64()))) + depositAmtB := sdk.OneInt().Add(sdk.NewInt(r.Int63n(balanceY.Amount.Int64()))) + depositCoins := sdk.NewCoins(sdk.NewCoin(DenomX, depositAmtA), sdk.NewCoin(DenomY, depositAmtB)) + _, err := simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch( + creatorAddr, pool.Id, depositCoins)) + require.NoError(t, err) + case withdraw: + totalPoolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawAmt := sdk.OneInt().Add(sdk.NewInt(r.Int63n(balancePoolCoin.Amount.Int64()))) + withdrawCoin := sdk.NewCoin(pool.PoolCoinDenom, sdk.MinInt(totalPoolCoin.Sub(sdk.OneInt()), withdrawAmt)) + _, err := simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch( + creatorAddr, pool.Id, withdrawCoin)) + require.NoError(t, err) + } + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + } + } +} + +func TestWithdrawEdgecase(t *testing.T) { + simapp, ctx := createTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + X, Y := sdk.NewInt(1_000_000), sdk.NewInt(10_000_000) + + depositCoins := sdk.NewCoins(sdk.NewCoin(DenomX, X), sdk.NewCoin(DenomY, Y)) + creatorAddr := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) + + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creatorAddr, types.DefaultPoolTypeID, depositCoins)) + require.NoError(t, err) + + creatorBalance := simapp.BankKeeper.GetBalance(ctx, creatorAddr, pool.PoolCoinDenom).Sub(sdk.NewCoin(pool.PoolCoinDenom, sdk.NewInt(2))) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, creatorBalance)) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + fmt.Println(simapp.LiquidityKeeper.GetPoolCoinTotal(ctx, pool)) + fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, creatorAddr)) + fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, pool.GetReserveAccount())) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewCoin(pool.PoolCoinDenom, sdk.OneInt()))) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + fmt.Println(simapp.LiquidityKeeper.GetPoolCoinTotal(ctx, pool)) + fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, creatorAddr)) + fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, pool.GetReserveAccount())) + + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewCoin(pool.PoolCoinDenom, sdk.OneInt()))) + require.NoError(t, err) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + fmt.Println(simapp.LiquidityKeeper.GetPoolCoinTotal(ctx, pool)) + fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, creatorAddr)) + fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, pool.GetReserveAccount())) +} + +func TestWithdrawEdgecase2(t *testing.T) { + simapp, ctx, pool, creatorAddr, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1500000)) + require.NoError(t, err) + + for i := 0; i < 1002; i++ { + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewInt64Coin(pool.PoolCoinDenom, 998))) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + } + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewInt64Coin(pool.PoolCoinDenom, 1))) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) +} + +func TestWithdrawSmallAmount(t *testing.T) { + simapp, ctx, pool, creatorAddr, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1500000)) + require.NoError(t, err) + + require.NotPanics(t, func() { + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewInt64Coin(pool.PoolCoinDenom, 1))) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + }) +} + +func TestGetReserveCoins(t *testing.T) { + simapp, ctx, pool, creatorAddr, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1000000)) + require.NoError(t, err) + + reserveCoins := simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.Len(t, reserveCoins, 2) + require.True(t, reserveCoins.AmountOf(DenomX).Equal(sdk.NewInt(1000000))) + require.True(t, reserveCoins.AmountOf(DenomY).Equal(sdk.NewInt(1000000))) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewInt64Coin(pool.PoolCoinDenom, 1000000))) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.Len(t, reserveCoins, 2) + require.True(t, reserveCoins.AmountOf(DenomX).IsZero()) + require.True(t, reserveCoins.AmountOf(DenomY).IsZero()) +} + +func TestDepositToDepletedPool(t *testing.T) { + simapp, ctx, pool, creatorAddr, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1000000)) + require.NoError(t, err) + params := simapp.LiquidityKeeper.GetParams(ctx) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + pc := simapp.BankKeeper.GetBalance(ctx, creatorAddr, pool.PoolCoinDenom) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, pc)) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + reserveCoins := simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.True(t, reserveCoins.AmountOf(DenomX).IsZero()) + require.True(t, reserveCoins.AmountOf(DenomY).IsZero()) + + require.True(t, simapp.LiquidityKeeper.IsDepletedPool(ctx, pool)) + + err = simapp.BankKeeper.SendCoins(ctx, creatorAddr, pool.GetReserveAccount(), sdk.NewCoins(sdk.NewInt64Coin(DenomX, 10000))) + require.NoError(t, err) + + // Deposit request must be rejected since the pool is depleted and + // depositing coins amount is smaller than MinInitDepositAmount. + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + depositCoins := sdk.NewCoins(sdk.NewInt64Coin(DenomX, 10000), sdk.NewInt64Coin(DenomY, 10000)) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(creatorAddr, pool.Id, depositCoins)) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.True(t, reserveCoins.AmountOf(DenomX).Equal(sdk.NewInt(10000))) + require.True(t, reserveCoins.AmountOf(DenomY).IsZero()) + creatorCoins := simapp.BankKeeper.GetAllBalances(ctx, creatorAddr) + require.True(t, creatorCoins.AmountOf(DenomX).Equal(sdk.NewInt(990000))) + require.True(t, creatorCoins.AmountOf(DenomY).Equal(sdk.NewInt(1000000))) + + // This time the request will be accepted since depositCoins + reserveCoins > MinInitDepositAmount. + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + depositCoins = sdk.NewCoins(sdk.NewInt64Coin(DenomX, 990000), sdk.NewInt64Coin(DenomY, 1000000)) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(creatorAddr, pool.Id, depositCoins)) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.True(t, reserveCoins.AmountOf(DenomX).Equal(sdk.NewInt(1000000))) + require.True(t, reserveCoins.AmountOf(DenomY).Equal(sdk.NewInt(1000000))) + creatorCoins = simapp.BankKeeper.GetAllBalances(ctx, creatorAddr) + require.True(t, creatorCoins.AmountOf(DenomX).Equal(sdk.NewInt(0))) + require.True(t, creatorCoins.AmountOf(DenomY).Equal(sdk.NewInt(0))) + require.True(t, creatorCoins.AmountOf(pool.PoolCoinDenom).Equal(params.InitPoolCoinMintAmount)) +} + +func TestDepositWithCoinsSent(t *testing.T) { + simapp, ctx, pool, _, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1000000)) + require.NoError(t, err) + + // Send extra coins to the pool reserve account, which causes the pool price to change. + // Any other coins(coins with denom "denomZ" here) than pool's reserve coins will not have any effect. + extraCoins := sdk.NewCoins( + sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 2000000), sdk.NewInt64Coin("denomZ", 1000000)) + addr := app.AddRandomTestAddr(simapp, ctx, extraCoins) + err = simapp.BankKeeper.SendCoins(ctx, addr, pool.GetReserveAccount(), extraCoins) + require.NoError(t, err) + reserveCoins := simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.Len(t, reserveCoins, 2) // denomZ coins are ignored + require.True(sdk.IntEq(t, sdk.NewInt(2000000), reserveCoins.AmountOf(DenomX))) + require.True(sdk.IntEq(t, sdk.NewInt(3000000), reserveCoins.AmountOf(DenomY))) + + // Add more coins to deposit. + depositCoins := sdk.NewCoins(sdk.NewInt64Coin(DenomX, 3000000), sdk.NewInt64Coin(DenomY, 3000000)) + app.SaveAccount(simapp, ctx, addr, depositCoins) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(addr, pool.Id, depositCoins)) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) + require.True(sdk.IntEq(t, sdk.NewInt(4000000), reserveCoins.AmountOf(DenomX))) + require.True(sdk.IntEq(t, sdk.NewInt(6000000), reserveCoins.AmountOf(DenomY))) + balances := simapp.BankKeeper.GetAllBalances(ctx, addr) + require.True(sdk.IntEq(t, sdk.NewInt(1000000), balances.AmountOf(DenomX))) + require.True(sdk.IntEq(t, sdk.NewInt(0), balances.AmountOf(DenomY))) + require.True(sdk.IntEq(t, sdk.NewInt(1000000), balances.AmountOf(pool.PoolCoinDenom))) +} + +func TestCreatePoolEqualDenom(t *testing.T) { + simapp, ctx := createTestInput() + params := types.DefaultParams() + simapp.LiquidityKeeper.SetParams(ctx, params) + addrs := app.AddTestAddrs(simapp, ctx, 1, params.PoolCreationFee) + + msg := types.NewMsgCreatePool(addrs[0], types.DefaultPoolTypeID, + sdk.Coins{ + sdk.NewCoin(DenomA, sdk.NewInt(1000000)), + sdk.NewCoin(DenomA, sdk.NewInt(1000000)), + }) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.ErrorIs(t, err, types.ErrEqualDenom) +} + +func TestOverflowAndZeroCases(t *testing.T) { + simapp, ctx := createTestInput() + params := types.DefaultParams() + simapp.LiquidityKeeper.SetParams(ctx, params) + keeper.BatchLogicInvariantCheckFlag = false + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + // Check overflow case on deposit + deposit := sdk.NewCoins( + sdk.NewCoin(denomA, sdk.NewInt(1_000_000)), + sdk.NewCoin(denomB, sdk.NewInt(2_000_000_000_000*1_000_000).MulRaw(1_000_000))) + hugeCoins := sdk.NewCoins( + sdk.NewCoin(denomA, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000)), + sdk.NewCoin(denomB, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000))) + hugeCoins2 := sdk.NewCoins( + sdk.NewCoin(denomA, sdk.NewInt(1_000_000_000_000_000_000)), + sdk.NewCoin(denomB, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit.Add(hugeCoins.Add(hugeCoins2...)...)) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, deposit) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + + depositorBalance := simapp.BankKeeper.GetAllBalances(ctx, addrs[0]) + depositMsg := types.NewMsgDepositWithinBatch(addrs[0], pools[0].Id, hugeCoins) + depositMsg2 := types.NewMsgDepositWithinBatch(addrs[0], pools[0].Id, hugeCoins2) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg2) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 2, len(msgs)) + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) + require.ErrorIs(t, err, types.ErrOverflowAmount) + err = simapp.LiquidityKeeper.RefundDeposit(ctx, msgs[0], poolBatch) + require.NoError(t, err) + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[1], poolBatch) + require.ErrorIs(t, err, types.ErrOverflowAmount) + err = simapp.LiquidityKeeper.RefundDeposit(ctx, msgs[1], poolBatch) + require.NoError(t, err) + + poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + depositorPoolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, poolCoinAfter) + require.Equal(t, poolCoinAfter, depositorPoolCoinBalance.Amount) + require.Equal(t, depositorBalance.AmountOf(pools[0].PoolCoinDenom), depositorPoolCoinBalance.Amount) + + hugeCoins3 := sdk.NewCoins( + sdk.NewCoin(denomA, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000)), + sdk.NewCoin(denomB, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000))) + depositMsg = types.NewMsgDepositWithinBatch(addrs[0], pools[0].Id, hugeCoins3) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + msgs = simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 3, len(msgs)) + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[2], poolBatch) + require.NoError(t, err) + + // Check overflow case on withdraw + depositorPoolCoinBalance = simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(addrs[0], pools[0].Id, depositorPoolCoinBalance.SubAmount(sdk.NewInt(1)))) + require.NoError(t, err) + + poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + withdrawMsgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + require.Equal(t, 1, len(withdrawMsgs)) + err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, withdrawMsgs[0], poolBatch) + require.ErrorIs(t, err, types.ErrOverflowAmount) + err = simapp.LiquidityKeeper.RefundWithdrawal(ctx, withdrawMsgs[0], poolBatch) + require.NoError(t, err) + + // Check overflow, division by zero case on swap + swapUserBalanceBefore := simapp.BankKeeper.GetAllBalances(ctx, addrs[0]) + offerCoinA := sdk.NewCoin(denomA, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000)) + orderPriceA := sdk.MustNewDecFromStr("110000000000000000000000000000000000000000000000000000000000.000000000000000001") + offerCoinB := sdk.NewCoin(denomB, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000)) + orderPriceB := sdk.MustNewDecFromStr("0.000000000000000001") + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, err = simapp.LiquidityKeeper.SwapWithinBatch( + ctx, + types.NewMsgSwapWithinBatch(addrs[0], pools[0].Id, types.DefaultSwapTypeID, offerCoinA, denomB, orderPriceA, params.SwapFeeRate), + 0) + require.ErrorIs(t, err, types.ErrOverflowAmount) + _, err = simapp.LiquidityKeeper.SwapWithinBatch( + ctx, + types.NewMsgSwapWithinBatch(addrs[0], pools[0].Id, types.DefaultSwapTypeID, offerCoinB, denomA, orderPriceB, params.SwapFeeRate), + 0) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + swapUserBalanceAfter := simapp.BankKeeper.GetAllBalances(ctx, addrs[0]) + require.Equal(t, swapUserBalanceBefore, swapUserBalanceAfter) + depositMsgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 0, len(depositMsgs)) + withdrawMsgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + require.Equal(t, 0, len(withdrawMsgs)) + swapMsgs := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStates(ctx, poolBatch) + require.Equal(t, 0, len(swapMsgs)) +} + +func TestExecuteBigDeposit(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + keeper.BatchLogicInvariantCheckFlag = false + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + // 2^63-1 + hugeInt := int64(9223372036854775807) + initDeposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(hugeInt)), sdk.NewCoin(denomB, sdk.NewInt(hugeInt))) + app.SaveAccount(simapp, ctx, addrs[0], initDeposit) + app.SaveAccount(simapp, ctx, addrs[1], initDeposit) + app.SaveAccount(simapp, ctx, addrs[2], initDeposit) + + createBalance := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(1*1000000)), sdk.NewCoin(denomB, sdk.NewInt(1*1000000))) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, createBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + poolCoinInit := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + require.Equal(t, poolCoinInit, sdk.NewInt(1*1000000)) + + depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, initDeposit) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + require.Equal(t, poolCoin.Sub(poolCoinInit), simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom).Amount) + + simapp.LiquidityKeeper.DeleteAllReadyPoolBatchDepositMsgStates(ctx, poolBatch) + + depositMsg = types.NewMsgDepositWithinBatch(addrs[2], pool.Id, initDeposit) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + msgs = simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + require.Equal(t, poolCoinAfter.Sub(poolCoin), simapp.BankKeeper.GetBalance(ctx, addrs[2], pool.PoolCoinDenom).Amount) + require.Equal(t, simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom).Amount, simapp.BankKeeper.GetBalance(ctx, addrs[2], pool.PoolCoinDenom).Amount) + + require.True(t, simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA).IsZero()) + require.True(t, simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB).IsZero()) + + // Error due to decimal operation exceeding precision + require.Equal(t, sdk.NewInt(8), simapp.BankKeeper.GetBalance(ctx, addrs[2], denomA).Amount) + require.Equal(t, sdk.NewInt(8), simapp.BankKeeper.GetBalance(ctx, addrs[2], denomB).Amount) + + poolCoinAmt := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) + state, err := simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(addrs[1], pool.Id, poolCoinAmt)) + require.NoError(t, err) + + err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, state, poolBatch) + require.NoError(t, err) + + balanceAfter := simapp.BankKeeper.GetAllBalances(ctx, addrs[1]) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // Error due to decimal operation exceeding precision + require.Equal(t, sdk.ZeroInt(), balanceAfter.AmountOf(pool.PoolCoinDenom)) + require.Equal(t, sdk.NewInt(-4), balanceAfter.AmountOf(denomA).SubRaw(hugeInt)) + require.Equal(t, sdk.NewInt(-4), balanceAfter.AmountOf(denomB).SubRaw(hugeInt)) +} diff --git a/x/liquidity/keeper/migration.go b/x/liquidity/keeper/migration.go new file mode 100644 index 00000000000..b7b58429d7c --- /dev/null +++ b/x/liquidity/keeper/migration.go @@ -0,0 +1,22 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + v043 "github.com/cosmos/gaia/v9/x/liquidity/legacy/v043" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + keeper Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(keeper Keeper) Migrator { + return Migrator{keeper: keeper} +} + +// Migrate1to2 migrates from version 1 to 2. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return v043.MigrateStore(ctx, m.keeper.storeKey) +} diff --git a/x/liquidity/keeper/msg_server.go b/x/liquidity/keeper/msg_server.go new file mode 100644 index 00000000000..db0b53f0afa --- /dev/null +++ b/x/liquidity/keeper/msg_server.go @@ -0,0 +1,167 @@ +package keeper + +// DONTCOVER + +// Although written in msg_server_test.go, it is approached at the keeper level rather than at the msgServer level +// so is not included in the coverage. + +import ( + "context" + "fmt" + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the distribution MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +// Message server, handler for CreatePool msg +func (k msgServer) CreatePool(goCtx context.Context, msg *types.MsgCreatePool) (*types.MsgCreatePoolResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if k.GetCircuitBreakerEnabled(ctx) { + return nil, types.ErrCircuitBreakerEnabled + } + + pool, err := k.Keeper.CreatePool(ctx, msg) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + sdk.NewEvent( + types.EventTypeCreatePool, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)), + sdk.NewAttribute(types.AttributeValuePoolTypeId, fmt.Sprintf("%d", msg.PoolTypeId)), + sdk.NewAttribute(types.AttributeValuePoolName, pool.Name()), + sdk.NewAttribute(types.AttributeValueReserveAccount, pool.ReserveAccountAddress), + sdk.NewAttribute(types.AttributeValueDepositCoins, msg.DepositCoins.String()), + sdk.NewAttribute(types.AttributeValuePoolCoinDenom, pool.PoolCoinDenom), + ), + }) + + return &types.MsgCreatePoolResponse{}, nil +} + +// Message server, handler for MsgDepositWithinBatch +func (k msgServer) DepositWithinBatch(goCtx context.Context, msg *types.MsgDepositWithinBatch) (*types.MsgDepositWithinBatchResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if k.GetCircuitBreakerEnabled(ctx) { + return nil, types.ErrCircuitBreakerEnabled + } + + poolBatch, found := k.GetPoolBatch(ctx, msg.PoolId) + if !found { + return nil, types.ErrPoolBatchNotExists + } + + batchMsg, err := k.Keeper.DepositWithinBatch(ctx, msg) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + sdk.NewEvent( + types.EventTypeDepositWithinBatch, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(batchMsg.Msg.PoolId, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(poolBatch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(batchMsg.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueDepositCoins, batchMsg.Msg.DepositCoins.String()), + ), + }) + + return &types.MsgDepositWithinBatchResponse{}, nil +} + +// Message server, handler for MsgWithdrawWithinBatch +func (k msgServer) WithdrawWithinBatch(goCtx context.Context, msg *types.MsgWithdrawWithinBatch) (*types.MsgWithdrawWithinBatchResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + poolBatch, found := k.GetPoolBatch(ctx, msg.PoolId) + if !found { + return nil, types.ErrPoolBatchNotExists + } + + batchMsg, err := k.Keeper.WithdrawWithinBatch(ctx, msg) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + sdk.NewEvent( + types.EventTypeWithdrawWithinBatch, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(batchMsg.Msg.PoolId, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(poolBatch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(batchMsg.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValuePoolCoinDenom, batchMsg.Msg.PoolCoin.Denom), + sdk.NewAttribute(types.AttributeValuePoolCoinAmount, batchMsg.Msg.PoolCoin.Amount.String()), + ), + }) + + return &types.MsgWithdrawWithinBatchResponse{}, nil +} + +// Message server, handler for MsgSwapWithinBatch +func (k msgServer) Swap(goCtx context.Context, msg *types.MsgSwapWithinBatch) (*types.MsgSwapWithinBatchResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if k.GetCircuitBreakerEnabled(ctx) { + return nil, types.ErrCircuitBreakerEnabled + } + + poolBatch, found := k.GetPoolBatch(ctx, msg.PoolId) + if !found { + return nil, types.ErrPoolBatchNotExists + } + + batchMsg, err := k.Keeper.SwapWithinBatch(ctx, msg, types.CancelOrderLifeSpan) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + sdk.NewEvent( + types.EventTypeSwapWithinBatch, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(batchMsg.Msg.PoolId, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(poolBatch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(batchMsg.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueSwapTypeId, strconv.FormatUint(uint64(batchMsg.Msg.SwapTypeId), 10)), + sdk.NewAttribute(types.AttributeValueOfferCoinDenom, batchMsg.Msg.OfferCoin.Denom), + sdk.NewAttribute(types.AttributeValueOfferCoinAmount, batchMsg.Msg.OfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueOfferCoinFeeAmount, batchMsg.Msg.OfferCoinFee.Amount.String()), + sdk.NewAttribute(types.AttributeValueDemandCoinDenom, batchMsg.Msg.DemandCoinDenom), + sdk.NewAttribute(types.AttributeValueOrderPrice, batchMsg.Msg.OrderPrice.String()), + ), + }) + + return &types.MsgSwapWithinBatchResponse{}, nil +} diff --git a/x/liquidity/keeper/msg_server_test.go b/x/liquidity/keeper/msg_server_test.go new file mode 100644 index 00000000000..f841678c081 --- /dev/null +++ b/x/liquidity/keeper/msg_server_test.go @@ -0,0 +1,431 @@ +package keeper_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// Although written in msg_server_test.go, it is approached at the keeper level rather than at the msgServer level +// so is not included in the coverage. + +func TestMsgCreatePool(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + require.Equal(t, 1, len(pools)) + require.Equal(t, uint64(1), pools[0].Id) + require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1) + require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1]) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.ErrorIs(t, err, types.ErrPoolAlreadyExists) +} + +func TestMsgDepositWithinBatch(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 4, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + app.SaveAccount(simapp, ctx, addrs[1], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + depositA = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA) + depositB = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB) + depositBalance = sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + + depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + depositorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) + require.Equal(t, poolCoin.Sub(poolCoinBefore), depositorBalance.Amount) +} + +func TestMsgWithdrawWithinBatch(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + pool := pools[0] + + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + + fmt.Println(poolCoinBefore, withdrawerPoolCoinBefore.Amount) + require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) + withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) + + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + require.NoError(t, err) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) + require.True(t, found) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + require.Equal(t, 1, len(msgs)) + + err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch) + require.NoError(t, err) + + poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + withdrawerPoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) + require.True(t, true, poolCoinAfter.IsZero()) + require.True(t, true, withdrawerPoolCoinAfter.IsZero()) + withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) + withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]), withdrawerDenomABalance.Amount) + require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), withdrawerDenomBBalance.Amount) +} + +func TestMsgGetLiquidityPoolMetadata(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + poolTypeID := types.DefaultPoolTypeID + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + + denomA := "uETH" + denomB := "uUSD" + denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) + + deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) + app.SaveAccount(simapp, ctx, addrs[0], deposit) + + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) + depositBalance := sdk.NewCoins(depositA, depositB) + + require.Equal(t, deposit, depositBalance) + + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + require.Equal(t, 1, len(pools)) + require.Equal(t, uint64(1), pools[0].Id) + require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1) + require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1]) + + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.ErrorIs(t, err, types.ErrPoolAlreadyExists) + + metaData := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pools[0]) + require.Equal(t, pools[0].Id, metaData.PoolId) + + reserveCoin := simapp.LiquidityKeeper.GetReserveCoins(ctx, pools[0]) + require.Equal(t, reserveCoin, metaData.ReserveCoins) + require.Equal(t, msg.DepositCoins, metaData.ReserveCoins) + + totalSupply := sdk.NewCoin(pools[0].PoolCoinDenom, simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0])) + require.Equal(t, totalSupply, metaData.PoolCoinTotalSupply) + require.Equal(t, creatorBalance, metaData.PoolCoinTotalSupply) +} + +func TestMsgSwapWithinBatch(t *testing.T) { + simapp, ctx := app.CreateTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + depositCoins := sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(1_000_000_000)), sdk.NewCoin(DenomY, sdk.NewInt(1_000_000_000))) + depositorAddr := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) + user := app.AddRandomTestAddr(simapp, ctx, sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(1_000_000_000)), sdk.NewCoin(DenomY, sdk.NewInt(1_000_000_000)))) + + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, &types.MsgCreatePool{ + PoolCreatorAddress: depositorAddr.String(), + PoolTypeId: types.DefaultPoolTypeID, + DepositCoins: depositCoins, + }) + require.NoError(t, err) + + cases := []struct { + expectedErr string // empty means no error expected + swapFeeRate sdk.Dec + msg *types.MsgSwapWithinBatch + afterBalance sdk.Coins + }{ + { + "", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(10000)), + OfferCoinFee: types.GetOfferCoinFee(sdk.NewCoin(DenomX, sdk.NewInt(10000)), params.SwapFeeRate), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("999989985denomX,1000009984denomY"), + }, + { + // bad offer coin denom + "bad offer coin fee", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(10000)), + OfferCoinFee: sdk.NewCoin(DenomY, sdk.NewInt(15)), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("1000000000denomX,1000000000denomY"), + }, + { + "bad offer coin fee", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(10000)), + OfferCoinFee: sdk.NewCoin(DenomX, sdk.NewInt(14)), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("1000000000denomX,1000000000denomY"), + }, + { + "bad offer coin fee", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(10000)), + OfferCoinFee: sdk.NewCoin(DenomX, sdk.NewInt(16)), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("1000000000denomX,1000000000denomY"), + }, + { + "", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(10001)), + OfferCoinFee: sdk.NewCoin(DenomX, sdk.NewInt(16)), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("999989983denomX,1000009984denomY"), + }, + { + "", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(100)), + OfferCoinFee: sdk.NewCoin(DenomX, sdk.NewInt(1)), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("999999899denomX,1000000098denomY"), + }, + { + "bad offer coin fee", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(100)), + OfferCoinFee: sdk.NewCoin(DenomX, sdk.NewInt(0)), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("1000000000denomX,1000000000denomY"), + }, + { + "", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(1000)), + OfferCoinFee: sdk.NewCoin(DenomX, sdk.NewInt(2)), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("999998998denomX,1000000997denomY"), + }, + { + "bad offer coin fee", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(1000)), + OfferCoinFee: sdk.NewCoin(DenomX, sdk.NewInt(1)), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("1000000000denomX,1000000000denomY"), + }, + { + "", + sdk.ZeroDec(), + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(1000)), + OfferCoinFee: sdk.NewCoin(DenomX, sdk.ZeroInt()), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("999999000denomX,1000000999denomY"), + }, + { + "does not match the reserve coin of the pool", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(10000)), + OfferCoinFee: types.GetOfferCoinFee(sdk.NewCoin(DenomX, sdk.NewInt(10000)), params.SwapFeeRate), + DemandCoinDenom: DenomA, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("1000000000denomX,1000000000denomY"), + }, + { + "can not exceed max order ratio of reserve coins that can be ordered at a order", + types.DefaultSwapFeeRate, + &types.MsgSwapWithinBatch{ + SwapRequesterAddress: user.String(), + PoolId: pool.Id, + SwapTypeId: pool.TypeId, + OfferCoin: sdk.NewCoin(DenomX, sdk.NewInt(100_000_001)), + OfferCoinFee: types.GetOfferCoinFee(sdk.NewCoin(DenomX, sdk.NewInt(100_000_001)), params.SwapFeeRate), + DemandCoinDenom: DenomY, + OrderPrice: sdk.MustNewDecFromStr("1.00002"), + }, + types.MustParseCoinsNormalized("1000000000denomX,1000000000denomY"), + }, + } + + for _, tc := range cases { + cacheCtx, _ := ctx.CacheContext() + cacheCtx = cacheCtx.WithBlockHeight(1) + params.SwapFeeRate = tc.swapFeeRate + simapp.LiquidityKeeper.SetParams(cacheCtx, params) + _, err = simapp.LiquidityKeeper.SwapWithinBatch(cacheCtx, tc.msg, types.CancelOrderLifeSpan) + if tc.expectedErr == "" { + require.NoError(t, err) + liquidity.EndBlocker(cacheCtx, simapp.LiquidityKeeper) + } else { + require.EqualError(t, err, tc.expectedErr) + } + moduleAccAddress := simapp.AccountKeeper.GetModuleAddress(types.ModuleName) + require.True(t, simapp.BankKeeper.GetAllBalances(cacheCtx, moduleAccAddress).IsZero()) + require.Equal(t, tc.afterBalance, simapp.BankKeeper.GetAllBalances(cacheCtx, user)) + } +} diff --git a/x/liquidity/keeper/querier.go b/x/liquidity/keeper/querier.go new file mode 100644 index 00000000000..d8f6ff9a80c --- /dev/null +++ b/x/liquidity/keeper/querier.go @@ -0,0 +1,64 @@ +package keeper + +// DONTCOVER +// client is excluded from test coverage in the poc phase milestone 1 and will be included in milestone 2 with completeness + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// NewQuerier creates a querier for liquidity REST endpoints +func NewQuerier(k Keeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err error) { + switch path[0] { + case types.QueryLiquidityPool: + return queryLiquidityPool(ctx, req, k, legacyQuerierCdc) + case types.QueryLiquidityPools: + return queryLiquidityPools(ctx, req, k, legacyQuerierCdc) + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path of liquidity module: %s", path[0]) + } + } +} + +// return query result data of the query liquidity pool +func queryLiquidityPool(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { + var params types.QueryLiquidityPoolParams + + if err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + liquidityPool, found := k.GetPool(ctx, params.PoolId) + if !found { + return nil, types.ErrPoolNotExists + } + + bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, liquidityPool) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil +} + +// return query result data of the query liquidity pools +func queryLiquidityPools(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { + var params types.QueryLiquidityPoolsParams + + if err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + liquidityPools := k.GetAllPools(ctx) + + bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, liquidityPools) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil +} diff --git a/x/liquidity/keeper/querier_test.go b/x/liquidity/keeper/querier_test.go new file mode 100644 index 00000000000..ac4c5b2e005 --- /dev/null +++ b/x/liquidity/keeper/querier_test.go @@ -0,0 +1,128 @@ +package keeper_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +const custom = "custom" + +func getQueriedLiquidityPool(t *testing.T, ctx sdk.Context, cdc *codec.LegacyAmino, querier sdk.Querier, poolID uint64) (types.Pool, error) { + query := abci.RequestQuery{ + Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryLiquidityPool}, "/"), + Data: cdc.MustMarshalJSON(types.QueryLiquidityPoolParams{PoolId: poolID}), + } + + pool := types.Pool{} + bz, err := querier(ctx, []string{types.QueryLiquidityPool}, query) + if err != nil { + return pool, err + } + require.Nil(t, cdc.UnmarshalJSON(bz, &pool)) + return pool, nil +} + +func getQueriedLiquidityPools(t *testing.T, ctx sdk.Context, cdc *codec.LegacyAmino, querier sdk.Querier) (types.Pools, error) { + queryDelParams := types.NewQueryLiquidityPoolsParams(1, 100) + bz, errRes := cdc.MarshalJSON(queryDelParams) + fmt.Println(bz, errRes) + query := abci.RequestQuery{ + Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryLiquidityPools}, "/"), + Data: bz, + } + + pools := types.Pools{} + bz, err := querier(ctx, []string{types.QueryLiquidityPools}, query) + if err != nil { + return pools, err + } + require.Nil(t, cdc.UnmarshalJSON(bz, &pools)) + return pools, nil +} + +func TestNewQuerier(t *testing.T) { + cdc := codec.NewLegacyAmino() + types.RegisterLegacyAminoCodec(cdc) + simapp := app.Setup(false) + ctx := simapp.BaseApp.NewContext(false, tmproto.Header{}) + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(1000000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + querier := keeper.NewQuerier(simapp.LiquidityKeeper, cdc) + + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, DenomX, DenomY, addrs[0]) + query := abci.RequestQuery{ + Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryLiquidityPool}, "/"), + Data: cdc.MustMarshalJSON(types.QueryLiquidityPoolParams{PoolId: poolID}), + } + queryFailCase := abci.RequestQuery{ + Path: strings.Join([]string{"failCustom", "failRoute", "failQuery"}, "/"), + Data: cdc.MustMarshalJSON(types.Pool{}), + } + pool := types.Pool{} + bz, err := querier(ctx, []string{types.QueryLiquidityPool}, query) + require.NoError(t, err) + require.Nil(t, cdc.UnmarshalJSON(bz, &pool)) + + bz, err = querier(ctx, []string{"fail"}, queryFailCase) + require.EqualError(t, err, "unknown query path of liquidity module: fail: unknown request") + err = cdc.UnmarshalJSON(bz, &pool) + require.EqualError(t, err, "UnmarshalJSON cannot decode empty bytes") +} + +func TestQueries(t *testing.T) { + cdc := codec.NewLegacyAmino() + types.RegisterLegacyAminoCodec(cdc) + + simapp := app.Setup(false) + ctx := simapp.BaseApp.NewContext(false, tmproto.Header{}) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + // denoms := []string{denomX, denomY} + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(1000000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + poolId2 := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, "testDenom", addrs[0]) + require.Equal(t, uint64(1), poolID) + require.Equal(t, uint64(2), poolId2) + + // begin block, init + app.TestDepositPool(t, simapp, ctx, X, Y, addrs[1:10], poolID, true) + + querier := keeper.NewQuerier(simapp.LiquidityKeeper, cdc) + + require.Equal(t, uint64(1), poolID) + poolRes, err := getQueriedLiquidityPool(t, ctx, cdc, querier, poolID) + require.NoError(t, err) + require.Equal(t, poolID, poolRes.Id) + require.Equal(t, types.DefaultPoolTypeID, poolRes.TypeId) + require.Equal(t, []string{DenomX, DenomY}, poolRes.ReserveCoinDenoms) + require.NotNil(t, poolRes.PoolCoinDenom) + require.NotNil(t, poolRes.ReserveAccountAddress) + + poolResEmpty, err := getQueriedLiquidityPool(t, ctx, cdc, querier, uint64(3)) + require.ErrorIs(t, err, types.ErrPoolNotExists) + require.Equal(t, uint64(0), poolResEmpty.Id) + + poolsRes, err := getQueriedLiquidityPools(t, ctx, cdc, querier) + require.NoError(t, err) + require.Equal(t, 2, len(poolsRes)) +} diff --git a/x/liquidity/keeper/store.go b/x/liquidity/keeper/store.go new file mode 100644 index 00000000000..6ddcfbbae9f --- /dev/null +++ b/x/liquidity/keeper/store.go @@ -0,0 +1,600 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + gogotypes "github.com/gogo/protobuf/types" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// GetPool reads from kvstore and returns a specific pool +func (k Keeper) GetPool(ctx sdk.Context, poolID uint64) (pool types.Pool, found bool) { + store := ctx.KVStore(k.storeKey) + key := types.GetPoolKey(poolID) + + value := store.Get(key) + if value == nil { + return pool, false + } + + pool = types.MustUnmarshalPool(k.cdc, value) + + return pool, true +} + +// SetPool sets to kvstore a specific pool +func (k Keeper) SetPool(ctx sdk.Context, pool types.Pool) { + store := ctx.KVStore(k.storeKey) + b := types.MustMarshalPool(k.cdc, pool) + store.Set(types.GetPoolKey(pool.Id), b) +} + +// delete from kvstore a specific liquidityPool +func (k Keeper) DeletePool(ctx sdk.Context, pool types.Pool) { + store := ctx.KVStore(k.storeKey) + Key := types.GetPoolKey(pool.Id) + store.Delete(Key) +} + +// IterateAllPools iterate through all of the liquidityPools +func (k Keeper) IterateAllPools(ctx sdk.Context, cb func(pool types.Pool) (stop bool)) { + store := ctx.KVStore(k.storeKey) + + iterator := sdk.KVStorePrefixIterator(store, types.PoolKeyPrefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + pool := types.MustUnmarshalPool(k.cdc, iterator.Value()) + if cb(pool) { + break + } + } +} + +// GetAllPools returns all liquidityPools used during genesis dump +func (k Keeper) GetAllPools(ctx sdk.Context) (pools []types.Pool) { + k.IterateAllPools(ctx, func(liquidityPool types.Pool) bool { + pools = append(pools, liquidityPool) + return false + }) + + return pools +} + +// GetNextPoolIDWithUpdate returns and increments the global Pool ID counter. +// If the global account number is not set, it initializes it with value 0. +func (k Keeper) GetNextPoolIDWithUpdate(ctx sdk.Context) uint64 { + store := ctx.KVStore(k.storeKey) + poolID := k.GetNextPoolID(ctx) + bz := k.cdc.MustMarshal(&gogotypes.UInt64Value{Value: poolID + 1}) + store.Set(types.GlobalLiquidityPoolIDKey, bz) + return poolID +} + +// GetNextPoolID returns next pool id for new pool, using index of latest pool id +func (k Keeper) GetNextPoolID(ctx sdk.Context) uint64 { + var poolID uint64 + store := ctx.KVStore(k.storeKey) + + bz := store.Get(types.GlobalLiquidityPoolIDKey) + if bz == nil { + // initialize the LiquidityPoolID + poolID = 1 + } else { + val := gogotypes.UInt64Value{} + + err := k.cdc.Unmarshal(bz, &val) + if err != nil { + panic(err) + } + + poolID = val.GetValue() + } + return poolID +} + +// GetPoolByReserveAccIndex reads from kvstore and return a specific liquidityPool indexed by given reserve account +func (k Keeper) GetPoolByReserveAccIndex(ctx sdk.Context, reserveAcc sdk.AccAddress) (pool types.Pool, found bool) { + store := ctx.KVStore(k.storeKey) + key := types.GetPoolByReserveAccIndexKey(reserveAcc) + + value := store.Get(key) + if value == nil { + return pool, false + } + + val := gogotypes.UInt64Value{} + err := k.cdc.Unmarshal(value, &val) + if err != nil { + return pool, false + } + poolID := val.GetValue() + return k.GetPool(ctx, poolID) +} + +// SetPoolByReserveAccIndex sets Index by ReserveAcc for pool duplication check +func (k Keeper) SetPoolByReserveAccIndex(ctx sdk.Context, pool types.Pool) { + store := ctx.KVStore(k.storeKey) + b := k.cdc.MustMarshal(&gogotypes.UInt64Value{Value: pool.Id}) + store.Set(types.GetPoolByReserveAccIndexKey(pool.GetReserveAccount()), b) +} + +// SetPoolAtomic sets pool with set global pool id index +1 and index by reserveAcc +func (k Keeper) SetPoolAtomic(ctx sdk.Context, pool types.Pool) types.Pool { + pool.Id = k.GetNextPoolIDWithUpdate(ctx) + k.SetPool(ctx, pool) + k.SetPoolByReserveAccIndex(ctx, pool) + return pool +} + +// GetPoolBatch returns a specific pool batch +func (k Keeper) GetPoolBatch(ctx sdk.Context, poolID uint64) (poolBatch types.PoolBatch, found bool) { + store := ctx.KVStore(k.storeKey) + key := types.GetPoolBatchKey(poolID) + + value := store.Get(key) + if value == nil { + return poolBatch, false + } + + poolBatch = types.MustUnmarshalPoolBatch(k.cdc, value) + + return poolBatch, true +} + +// GetAllPoolBatches returns all batches of the all existed liquidity pools +func (k Keeper) GetAllPoolBatches(ctx sdk.Context) (poolBatches []types.PoolBatch) { + k.IterateAllPoolBatches(ctx, func(poolBatch types.PoolBatch) bool { + poolBatches = append(poolBatches, poolBatch) + return false + }) + + return poolBatches +} + +// IterateAllPoolBatches iterate through all of the pool batches +func (k Keeper) IterateAllPoolBatches(ctx sdk.Context, cb func(poolBatch types.PoolBatch) (stop bool)) { + store := ctx.KVStore(k.storeKey) + + iterator := sdk.KVStorePrefixIterator(store, types.PoolBatchKeyPrefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + poolBatch := types.MustUnmarshalPoolBatch(k.cdc, iterator.Value()) + if cb(poolBatch) { + break + } + } +} + +// DeletePoolBatch deletes batch of the pool, it used for test case +func (k Keeper) DeletePoolBatch(ctx sdk.Context, poolBatch types.PoolBatch) { + store := ctx.KVStore(k.storeKey) + batchKey := types.GetPoolBatchKey(poolBatch.PoolId) + store.Delete(batchKey) +} + +// SetPoolBatch sets batch of the pool, with current state +func (k Keeper) SetPoolBatch(ctx sdk.Context, poolBatch types.PoolBatch) { + store := ctx.KVStore(k.storeKey) + b := types.MustMarshalPoolBatch(k.cdc, poolBatch) + store.Set(types.GetPoolBatchKey(poolBatch.PoolId), b) +} + +// GetPoolBatchDepositMsgState returns a specific DepositMsgState +func (k Keeper) GetPoolBatchDepositMsgState(ctx sdk.Context, poolID, msgIndex uint64) (state types.DepositMsgState, found bool) { + store := ctx.KVStore(k.storeKey) + key := types.GetPoolBatchDepositMsgStateIndexKey(poolID, msgIndex) + + value := store.Get(key) + if value == nil { + return state, false + } + + state = types.MustUnmarshalDepositMsgState(k.cdc, value) + return state, true +} + +// SetPoolBatchDepositMsgState sets deposit msg state of the pool batch, with current state +func (k Keeper) SetPoolBatchDepositMsgState(ctx sdk.Context, poolID uint64, state types.DepositMsgState) { + store := ctx.KVStore(k.storeKey) + b := types.MustMarshalDepositMsgState(k.cdc, state) + store.Set(types.GetPoolBatchDepositMsgStateIndexKey(poolID, state.MsgIndex), b) +} + +// SetPoolBatchDepositMsgStatesByPointer sets deposit batch msgs of the pool batch, with current state using pointers +func (k Keeper) SetPoolBatchDepositMsgStatesByPointer(ctx sdk.Context, poolID uint64, states []*types.DepositMsgState) { + store := ctx.KVStore(k.storeKey) + for _, state := range states { + if poolID != state.Msg.PoolId { + continue + } + b := types.MustMarshalDepositMsgState(k.cdc, *state) + store.Set(types.GetPoolBatchDepositMsgStateIndexKey(poolID, state.MsgIndex), b) + } +} + +// SetPoolBatchDepositMsgStates sets deposit batch msgs of the pool batch, with current state +func (k Keeper) SetPoolBatchDepositMsgStates(ctx sdk.Context, poolID uint64, states []types.DepositMsgState) { + store := ctx.KVStore(k.storeKey) + for _, state := range states { + if poolID != state.Msg.PoolId { + continue + } + b := types.MustMarshalDepositMsgState(k.cdc, state) + store.Set(types.GetPoolBatchDepositMsgStateIndexKey(poolID, state.MsgIndex), b) + } +} + +// IterateAllPoolBatchDepositMsgStates iterate through all of the DepositMsgStates in the batch +func (k Keeper) IterateAllPoolBatchDepositMsgStates(ctx sdk.Context, poolBatch types.PoolBatch, cb func(state types.DepositMsgState) (stop bool)) { + store := ctx.KVStore(k.storeKey) + + prefix := types.GetPoolBatchDepositMsgStatesPrefix(poolBatch.PoolId) + iterator := sdk.KVStorePrefixIterator(store, prefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + state := types.MustUnmarshalDepositMsgState(k.cdc, iterator.Value()) + if cb(state) { + break + } + } +} + +// IterateAllDepositMsgStates iterate through all of the DepositMsgState of all batches +func (k Keeper) IterateAllDepositMsgStates(ctx sdk.Context, cb func(state types.DepositMsgState) (stop bool)) { + store := ctx.KVStore(k.storeKey) + + prefix := types.PoolBatchDepositMsgStateIndexKeyPrefix + iterator := sdk.KVStorePrefixIterator(store, prefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + state := types.MustUnmarshalDepositMsgState(k.cdc, iterator.Value()) + if cb(state) { + break + } + } +} + +// GetAllDepositMsgStates returns all BatchDepositMsgs for all batches. +func (k Keeper) GetAllDepositMsgStates(ctx sdk.Context) (states []types.DepositMsgState) { + k.IterateAllDepositMsgStates(ctx, func(state types.DepositMsgState) bool { + states = append(states, state) + return false + }) + return states +} + +// GetAllPoolBatchDepositMsgs returns all BatchDepositMsgs indexed by the pool batch +func (k Keeper) GetAllPoolBatchDepositMsgs(ctx sdk.Context, poolBatch types.PoolBatch) (states []types.DepositMsgState) { + k.IterateAllPoolBatchDepositMsgStates(ctx, poolBatch, func(state types.DepositMsgState) bool { + states = append(states, state) + return false + }) + return states +} + +// GetAllPoolBatchDepositMsgStatesNotToBeDeleted returns all Not toDelete BatchDepositMsgs indexed by the liquidityPoolBatch +func (k Keeper) GetAllPoolBatchDepositMsgStatesNotToBeDeleted(ctx sdk.Context, poolBatch types.PoolBatch) (states []types.DepositMsgState) { + k.IterateAllPoolBatchDepositMsgStates(ctx, poolBatch, func(state types.DepositMsgState) bool { + if !state.ToBeDeleted { + states = append(states, state) + } + return false + }) + return states +} + +// GetAllRemainingPoolBatchDepositMsgStates returns all remaining DepositMsgStates after endblock, +// which are executed but not to be deleted +func (k Keeper) GetAllRemainingPoolBatchDepositMsgStates(ctx sdk.Context, poolBatch types.PoolBatch) (states []*types.DepositMsgState) { + k.IterateAllPoolBatchDepositMsgStates(ctx, poolBatch, func(state types.DepositMsgState) bool { + if state.Executed && !state.ToBeDeleted { + states = append(states, &state) + } + return false + }) + return states +} + +// delete deposit batch msgs of the liquidity pool batch which has state ToBeDeleted +func (k Keeper) DeleteAllReadyPoolBatchDepositMsgStates(ctx sdk.Context, poolBatch types.PoolBatch) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.GetPoolBatchDepositMsgStatesPrefix(poolBatch.PoolId)) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + state := types.MustUnmarshalDepositMsgState(k.cdc, iterator.Value()) + if state.ToBeDeleted { + store.Delete(iterator.Key()) + } + } +} + +// return a specific liquidityPoolBatchWithdrawMsg +func (k Keeper) GetPoolBatchWithdrawMsgState(ctx sdk.Context, poolID, msgIndex uint64) (state types.WithdrawMsgState, found bool) { + store := ctx.KVStore(k.storeKey) + key := types.GetPoolBatchWithdrawMsgStateIndexKey(poolID, msgIndex) + + value := store.Get(key) + if value == nil { + return state, false + } + + state = types.MustUnmarshalWithdrawMsgState(k.cdc, value) + return state, true +} + +// set withdraw batch msg of the liquidity pool batch, with current state +func (k Keeper) SetPoolBatchWithdrawMsgState(ctx sdk.Context, poolID uint64, state types.WithdrawMsgState) { + store := ctx.KVStore(k.storeKey) + b := types.MustMarshalWithdrawMsgState(k.cdc, state) + store.Set(types.GetPoolBatchWithdrawMsgStateIndexKey(poolID, state.MsgIndex), b) +} + +// set withdraw batch msgs of the liquidity pool batch, with current state using pointers +func (k Keeper) SetPoolBatchWithdrawMsgStatesByPointer(ctx sdk.Context, poolID uint64, states []*types.WithdrawMsgState) { + store := ctx.KVStore(k.storeKey) + for _, state := range states { + if poolID != state.Msg.PoolId { + continue + } + b := types.MustMarshalWithdrawMsgState(k.cdc, *state) + store.Set(types.GetPoolBatchWithdrawMsgStateIndexKey(poolID, state.MsgIndex), b) + } +} + +// set withdraw batch msgs of the pool batch, with current state +func (k Keeper) SetPoolBatchWithdrawMsgStates(ctx sdk.Context, poolID uint64, states []types.WithdrawMsgState) { + store := ctx.KVStore(k.storeKey) + for _, state := range states { + if poolID != state.Msg.PoolId { + continue + } + b := types.MustMarshalWithdrawMsgState(k.cdc, state) + store.Set(types.GetPoolBatchWithdrawMsgStateIndexKey(poolID, state.MsgIndex), b) + } +} + +// IterateAllPoolBatchWithdrawMsgStates iterate through all of the LiquidityPoolBatchWithdrawMsgs +func (k Keeper) IterateAllPoolBatchWithdrawMsgStates(ctx sdk.Context, poolBatch types.PoolBatch, cb func(state types.WithdrawMsgState) (stop bool)) { + store := ctx.KVStore(k.storeKey) + + prefix := types.GetPoolBatchWithdrawMsgsPrefix(poolBatch.PoolId) + iterator := sdk.KVStorePrefixIterator(store, prefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + state := types.MustUnmarshalWithdrawMsgState(k.cdc, iterator.Value()) + if cb(state) { + break + } + } +} + +// IterateAllWithdrawMsgStates iterate through all of the WithdrawMsgState of all batches +func (k Keeper) IterateAllWithdrawMsgStates(ctx sdk.Context, cb func(state types.WithdrawMsgState) (stop bool)) { + store := ctx.KVStore(k.storeKey) + + prefix := types.PoolBatchWithdrawMsgStateIndexKeyPrefix + iterator := sdk.KVStorePrefixIterator(store, prefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + state := types.MustUnmarshalWithdrawMsgState(k.cdc, iterator.Value()) + if cb(state) { + break + } + } +} + +// GetAllWithdrawMsgStates returns all BatchWithdrawMsgs for all batches +func (k Keeper) GetAllWithdrawMsgStates(ctx sdk.Context) (states []types.WithdrawMsgState) { + k.IterateAllWithdrawMsgStates(ctx, func(state types.WithdrawMsgState) bool { + states = append(states, state) + return false + }) + return states +} + +// GetAllPoolBatchWithdrawMsgStates returns all BatchWithdrawMsgs indexed by the liquidityPoolBatch +func (k Keeper) GetAllPoolBatchWithdrawMsgStates(ctx sdk.Context, poolBatch types.PoolBatch) (states []types.WithdrawMsgState) { + k.IterateAllPoolBatchWithdrawMsgStates(ctx, poolBatch, func(state types.WithdrawMsgState) bool { + states = append(states, state) + return false + }) + return states +} + +// GetAllPoolBatchWithdrawMsgStatesNotToBeDeleted returns all Not to delete BatchWithdrawMsgs indexed by the liquidityPoolBatch +func (k Keeper) GetAllPoolBatchWithdrawMsgStatesNotToBeDeleted(ctx sdk.Context, poolBatch types.PoolBatch) (states []types.WithdrawMsgState) { + k.IterateAllPoolBatchWithdrawMsgStates(ctx, poolBatch, func(state types.WithdrawMsgState) bool { + if !state.ToBeDeleted { + states = append(states, state) + } + return false + }) + return states +} + +// GetAllRemainingPoolBatchWithdrawMsgStates returns All only remaining BatchWithdrawMsgs after endblock, executed but not toDelete +func (k Keeper) GetAllRemainingPoolBatchWithdrawMsgStates(ctx sdk.Context, poolBatch types.PoolBatch) (states []*types.WithdrawMsgState) { + k.IterateAllPoolBatchWithdrawMsgStates(ctx, poolBatch, func(state types.WithdrawMsgState) bool { + if state.Executed && !state.ToBeDeleted { + states = append(states, &state) + } + return false + }) + return states +} + +// delete withdraw batch msgs of the liquidity pool batch which has state ToBeDeleted +func (k Keeper) DeleteAllReadyPoolBatchWithdrawMsgStates(ctx sdk.Context, poolBatch types.PoolBatch) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.GetPoolBatchWithdrawMsgsPrefix(poolBatch.PoolId)) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + state := types.MustUnmarshalWithdrawMsgState(k.cdc, iterator.Value()) + if state.ToBeDeleted { + store.Delete(iterator.Key()) + } + } +} + +// return a specific SwapMsgState given the pool_id with the msg_index +func (k Keeper) GetPoolBatchSwapMsgState(ctx sdk.Context, poolID, msgIndex uint64) (state types.SwapMsgState, found bool) { + store := ctx.KVStore(k.storeKey) + key := types.GetPoolBatchSwapMsgStateIndexKey(poolID, msgIndex) + + value := store.Get(key) + if value == nil { + return state, false + } + + state = types.MustUnmarshalSwapMsgState(k.cdc, value) + return state, true +} + +// set swap batch msg of the liquidity pool batch, with current state +func (k Keeper) SetPoolBatchSwapMsgState(ctx sdk.Context, poolID uint64, state types.SwapMsgState) { + store := ctx.KVStore(k.storeKey) + b := types.MustMarshalSwapMsgState(k.cdc, state) + store.Set(types.GetPoolBatchSwapMsgStateIndexKey(poolID, state.MsgIndex), b) +} + +// Delete swap batch msg of the liquidity pool batch, it used for test case +func (k Keeper) DeletePoolBatchSwapMsgState(ctx sdk.Context, poolID uint64, msgIndex uint64) { + store := ctx.KVStore(k.storeKey) + batchKey := types.GetPoolBatchSwapMsgStateIndexKey(poolID, msgIndex) + store.Delete(batchKey) +} + +// IterateAllPoolBatchSwapMsgStates iterate through all of the LiquidityPoolBatchSwapMsgs +func (k Keeper) IterateAllPoolBatchSwapMsgStates(ctx sdk.Context, poolBatch types.PoolBatch, cb func(state types.SwapMsgState) (stop bool)) { + store := ctx.KVStore(k.storeKey) + + prefix := types.GetPoolBatchSwapMsgStatesPrefix(poolBatch.PoolId) + iterator := sdk.KVStorePrefixIterator(store, prefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + state := types.MustUnmarshalSwapMsgState(k.cdc, iterator.Value()) + if cb(state) { + break + } + } +} + +// IterateAllSwapMsgStates iterate through all of the SwapMsgState of all batches +func (k Keeper) IterateAllSwapMsgStates(ctx sdk.Context, cb func(state types.SwapMsgState) (stop bool)) { + store := ctx.KVStore(k.storeKey) + + prefix := types.PoolBatchSwapMsgStateIndexKeyPrefix + iterator := sdk.KVStorePrefixIterator(store, prefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + state := types.MustUnmarshalSwapMsgState(k.cdc, iterator.Value()) + if cb(state) { + break + } + } +} + +// GetAllSwapMsgStates returns all BatchSwapMsgs of all batches +func (k Keeper) GetAllSwapMsgStates(ctx sdk.Context) (states []types.SwapMsgState) { + k.IterateAllSwapMsgStates(ctx, func(state types.SwapMsgState) bool { + states = append(states, state) + return false + }) + return states +} + +// delete swap batch msgs of the liquidity pool batch which has state ToBeDeleted +func (k Keeper) DeleteAllReadyPoolBatchSwapMsgStates(ctx sdk.Context, poolBatch types.PoolBatch) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.GetPoolBatchSwapMsgStatesPrefix(poolBatch.PoolId)) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + state := types.MustUnmarshalSwapMsgState(k.cdc, iterator.Value()) + if state.ToBeDeleted { + store.Delete(iterator.Key()) + } + } +} + +// GetAllPoolBatchSwapMsgStatesAsPointer returns all BatchSwapMsgs pointer indexed by the liquidityPoolBatch +func (k Keeper) GetAllPoolBatchSwapMsgStatesAsPointer(ctx sdk.Context, poolBatch types.PoolBatch) (states []*types.SwapMsgState) { + k.IterateAllPoolBatchSwapMsgStates(ctx, poolBatch, func(state types.SwapMsgState) bool { + states = append(states, &state) + return false + }) + return states +} + +// GetAllPoolBatchSwapMsgStates returns all BatchSwapMsgs indexed by the liquidityPoolBatch +func (k Keeper) GetAllPoolBatchSwapMsgStates(ctx sdk.Context, poolBatch types.PoolBatch) (states []types.SwapMsgState) { + k.IterateAllPoolBatchSwapMsgStates(ctx, poolBatch, func(state types.SwapMsgState) bool { + states = append(states, state) + return false + }) + return states +} + +// GetAllNotProcessedPoolBatchSwapMsgStates returns All only not processed swap msgs, not executed with not succeed and not toDelete BatchSwapMsgs indexed by the liquidityPoolBatch +func (k Keeper) GetAllNotProcessedPoolBatchSwapMsgStates(ctx sdk.Context, poolBatch types.PoolBatch) (states []*types.SwapMsgState) { + k.IterateAllPoolBatchSwapMsgStates(ctx, poolBatch, func(state types.SwapMsgState) bool { + if !state.Executed && !state.Succeeded && !state.ToBeDeleted { + states = append(states, &state) + } + return false + }) + return states +} + +// GetAllRemainingPoolBatchSwapMsgStates returns All only remaining after endblock swap msgs, executed but not toDelete +func (k Keeper) GetAllRemainingPoolBatchSwapMsgStates(ctx sdk.Context, poolBatch types.PoolBatch) (states []*types.SwapMsgState) { + k.IterateAllPoolBatchSwapMsgStates(ctx, poolBatch, func(state types.SwapMsgState) bool { + if state.Executed && !state.ToBeDeleted { + states = append(states, &state) + } + return false + }) + return states +} + +// GetAllPoolBatchSwapMsgStatesNotToBeDeleted returns All only not to delete swap msgs +func (k Keeper) GetAllPoolBatchSwapMsgStatesNotToBeDeleted(ctx sdk.Context, poolBatch types.PoolBatch) (states []*types.SwapMsgState) { + k.IterateAllPoolBatchSwapMsgStates(ctx, poolBatch, func(state types.SwapMsgState) bool { + if !state.ToBeDeleted { + states = append(states, &state) + } + return false + }) + return states +} + +// set swap batch msgs of the liquidity pool batch, with current state using pointers +func (k Keeper) SetPoolBatchSwapMsgStatesByPointer(ctx sdk.Context, poolID uint64, states []*types.SwapMsgState) { + store := ctx.KVStore(k.storeKey) + for _, state := range states { + if poolID != state.Msg.PoolId { + continue + } + b := types.MustMarshalSwapMsgState(k.cdc, *state) + store.Set(types.GetPoolBatchSwapMsgStateIndexKey(poolID, state.MsgIndex), b) + } +} + +// set swap batch msgs of the liquidity pool batch, with current state +func (k Keeper) SetPoolBatchSwapMsgStates(ctx sdk.Context, poolID uint64, states []types.SwapMsgState) { + store := ctx.KVStore(k.storeKey) + for _, state := range states { + if poolID != state.Msg.PoolId { + continue + } + b := types.MustMarshalSwapMsgState(k.cdc, state) + store.Set(types.GetPoolBatchSwapMsgStateIndexKey(poolID, state.MsgIndex), b) + } +} diff --git a/x/liquidity/keeper/store_test.go b/x/liquidity/keeper/store_test.go new file mode 100644 index 00000000000..5c2cab71eb9 --- /dev/null +++ b/x/liquidity/keeper/store_test.go @@ -0,0 +1,355 @@ +package keeper_test + +import ( + "math/rand" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestGetAllLiquidityPoolBatchSwapMsgs(t *testing.T) { + for seed := int64(0); seed < 100; seed++ { + r := rand.New(rand.NewSource(seed)) + + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + // define test denom X, Y for Liquidity Pool + denomX := "denomX" + denomY := "denomY" + denomX, denomY = types.AlphabeticalDenomPair(denomX, denomY) + + // get random X, Y amount for create pool + X, Y := app.GetRandPoolAmt(r, params.MinInitDepositAmount) + deposit := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) + + // set pool creator account, balance for deposit + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + app.SaveAccount(simapp, ctx, addrs[0], deposit) // pool creator + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomX) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomY) + depositBalance := sdk.NewCoins(depositA, depositB) + require.Equal(t, deposit, depositBalance) + + // create Liquidity pool + poolTypeID := types.DefaultPoolTypeID + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + var xToY []*types.MsgSwapWithinBatch // buying Y from X + var yToX []*types.MsgSwapWithinBatch // selling Y for X + + // make random orders, set buyer, seller accounts for the orders + xToY, yToX = app.GetRandomOrders(denomX, denomY, X, Y, r, 11, 11) + buyerAddrs := app.AddTestAddrsIncremental(simapp, ctx, len(xToY), sdk.ZeroInt()) + sellerAddrs := app.AddTestAddrsIncremental(simapp, ctx, len(yToX), sdk.ZeroInt()) + + poolID := uint64(1) + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.Equal(t, uint64(1), poolBatch.SwapMsgIndex) + + for i, msg := range xToY { + app.SaveAccountWithFee(simapp, ctx, buyerAddrs[i], sdk.NewCoins(msg.OfferCoin), msg.OfferCoin) + msg.SwapRequesterAddress = buyerAddrs[i].String() + msg.PoolId = pool.Id + msg.OfferCoinFee = types.GetOfferCoinFee(msg.OfferCoin, params.SwapFeeRate) + } + for i, msg := range yToX { + app.SaveAccountWithFee(simapp, ctx, sellerAddrs[i], sdk.NewCoins(msg.OfferCoin), msg.OfferCoin) + msg.SwapRequesterAddress = sellerAddrs[i].String() + msg.PoolId = pool.Id + msg.OfferCoinFee = types.GetOfferCoinFee(msg.OfferCoin, params.SwapFeeRate) + } + + // handle msgs, set order msgs to batch + for _, msg := range xToY[:10] { + _, err := simapp.LiquidityKeeper.SwapWithinBatch(ctx, msg, 0) + require.NoError(t, err) + } + for _, msg := range yToX[:10] { + _, err := simapp.LiquidityKeeper.SwapWithinBatch(ctx, msg, 0) + require.NoError(t, err) + } + + msgs := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, poolBatch) + require.Equal(t, 20, len(msgs)) + + simapp.LiquidityKeeper.IterateAllPoolBatchSwapMsgStates(ctx, poolBatch, func(msg types.SwapMsgState) bool { + if msg.MsgIndex%2 == 1 { + simapp.LiquidityKeeper.DeletePoolBatchSwapMsgState(ctx, msg.Msg.PoolId, msg.MsgIndex) + } + return false + }) + + msgs = simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, poolBatch) + require.Equal(t, 10, len(msgs)) + + poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.Equal(t, uint64(21), poolBatch.SwapMsgIndex) + + poolBatch.SwapMsgIndex = uint64(18446744073709551610) + simapp.LiquidityKeeper.SetPoolBatch(ctx, poolBatch) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, xToY[10], 0) + require.NoError(t, err) + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, yToX[10], 0) + require.NoError(t, err) + + msgs = simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, poolBatch) + require.Equal(t, 12, len(msgs)) + require.Equal(t, xToY[10], msgs[10].Msg) + require.Equal(t, yToX[10], msgs[11].Msg) + } +} + +func TestGetAllNotProcessedPoolBatchSwapMsgs(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(1000000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + // begin block, init + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, true) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, true) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + price, _ := sdk.NewDecFromStr("1.1") + offerCoins := []sdk.Coin{sdk.NewCoin(denomX, sdk.NewInt(10000)), sdk.NewCoin(denomX, sdk.NewInt(10000)), sdk.NewCoin(denomX, sdk.NewInt(10000))} + orderPrices := []sdk.Dec{price, price, price} + orderAddrs := addrs[1:4] + batchMsgs, _ := app.TestSwapPool(t, simapp, ctx, offerCoins, orderPrices, orderAddrs, poolID, false) + batchMsgs2, batch := app.TestSwapPool(t, simapp, ctx, offerCoins, orderPrices, orderAddrs, poolID, false) + require.Equal(t, 3, len(batchMsgs)) + for _, msg := range batchMsgs2 { + msg.Executed = true + msg.Succeeded = true + msg.ToBeDeleted = true + } + require.Equal(t, 3, len(batchMsgs2)) + simapp.LiquidityKeeper.SetPoolBatchSwapMsgStatesByPointer(ctx, poolID, batchMsgs2) + + resultMsgs := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, batch) + resultProcessedMsgs := simapp.LiquidityKeeper.GetAllNotProcessedPoolBatchSwapMsgStates(ctx, batch) + require.Equal(t, 6, len(resultMsgs)) + require.Equal(t, 3, len(resultProcessedMsgs)) +} + +func TestIterateAllBatchMsgs(t *testing.T) { + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + denomA, denomB := types.AlphabeticalDenomPair("denomA", "denomB") + + X := sdk.NewInt(1000000000) + Y := sdk.NewInt(500000000) + A := sdk.NewInt(500000000) + B := sdk.NewInt(1000000000) + + addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + poolId2 := app.TestCreatePool(t, simapp, ctx, A, B, denomA, denomB, addrs[4]) + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + + price, _ := sdk.NewDecFromStr("1.1") + priceY, _ := sdk.NewDecFromStr("1.2") + xOfferCoins := []sdk.Coin{sdk.NewCoin(denomX, sdk.NewInt(10000))} + yOfferCoins := []sdk.Coin{sdk.NewCoin(denomY, sdk.NewInt(5000))} + + xOrderPrices := []sdk.Dec{price} + yOrderPrices := []sdk.Dec{priceY} + xOrderAddrs := addrs[1:2] + yOrderAddrs := addrs[2:3] + + offerCoins2 := []sdk.Coin{sdk.NewCoin(denomA, sdk.NewInt(5000))} + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + app.TestDepositPool(t, simapp, ctx, A, B.QuoRaw(10), addrs[4:5], poolId2, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(1000), addrs[4:5], poolId2, false) + app.TestSwapPool(t, simapp, ctx, offerCoins2, xOrderPrices, addrs[4:5], poolId2, true) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + app.TestDepositPool(t, simapp, ctx, A, B.QuoRaw(10), addrs[4:5], poolId2, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(1000), addrs[4:5], poolId2, false) + app.TestSwapPool(t, simapp, ctx, offerCoins2, xOrderPrices, addrs[4:5], poolId2, true) + + // next block, + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + // Reinitialize batch messages that were not executed in the previous batch and delete batch messages that were executed or ready to delete. + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X.QuoRaw(10), Y, addrs[1:2], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestDepositPool(t, simapp, ctx, X, Y.QuoRaw(10), addrs[2:3], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(50), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(500), addrs[1:2], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(50), addrs[2:3], poolID, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(500), addrs[2:3], poolID, false) + + depositMsgsRemaining := simapp.LiquidityKeeper.GetAllRemainingPoolBatchDepositMsgStates(ctx, batch) + require.Equal(t, 0, len(depositMsgsRemaining)) + + var depositMsgs []types.DepositMsgState + simapp.LiquidityKeeper.IterateAllDepositMsgStates(ctx, func(msg types.DepositMsgState) bool { + depositMsgs = append(depositMsgs, msg) + return false + }) + require.Equal(t, 4, len(depositMsgs)) + + depositMsgs[0].ToBeDeleted = true + simapp.LiquidityKeeper.SetPoolBatchDepositMsgStates(ctx, poolID, []types.DepositMsgState{depositMsgs[0]}) + depositMsgsNotToDelete := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgStatesNotToBeDeleted(ctx, batch) + require.Equal(t, 3, len(depositMsgsNotToDelete)) + + var withdrawMsgs []types.WithdrawMsgState + simapp.LiquidityKeeper.IterateAllWithdrawMsgStates(ctx, func(msg types.WithdrawMsgState) bool { + withdrawMsgs = append(withdrawMsgs, msg) + return false + }) + withdrawMsgs[0].ToBeDeleted = true + simapp.LiquidityKeeper.SetPoolBatchWithdrawMsgStates(ctx, poolID, withdrawMsgs[0:1]) + + withdrawMsgsNotToDelete := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStatesNotToBeDeleted(ctx, batch) + require.Equal(t, 4, len(withdrawMsgs)) + require.Equal(t, 3, len(withdrawMsgsNotToDelete)) + require.NotEqual(t, withdrawMsgsNotToDelete, withdrawMsgs) + + app.TestDepositPool(t, simapp, ctx, A, B.QuoRaw(10), addrs[4:5], poolId2, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(1000), addrs[4:5], poolId2, false) + + depositMsgs = simapp.LiquidityKeeper.GetAllDepositMsgStates(ctx) + require.Equal(t, 5, len(depositMsgs)) + withdrawMsgs = simapp.LiquidityKeeper.GetAllWithdrawMsgStates(ctx) + require.Equal(t, 5, len(depositMsgs)) + + var depositMsgs2 []types.DepositMsgState + simapp.LiquidityKeeper.IterateAllDepositMsgStates(ctx, func(msg types.DepositMsgState) bool { + depositMsgs2 = append(depositMsgs2, msg) + return false + }) + + var withdrawMsgs2 []types.WithdrawMsgState + simapp.LiquidityKeeper.IterateAllWithdrawMsgStates(ctx, func(msg types.WithdrawMsgState) bool { + withdrawMsgs2 = append(withdrawMsgs2, msg) + return false + }) + + require.Equal(t, 5, len(depositMsgs2)) + + require.Equal(t, 5, len(withdrawMsgs2)) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + depositMsgsRemaining = simapp.LiquidityKeeper.GetAllRemainingPoolBatchDepositMsgStates(ctx, batch) + require.Equal(t, 0, len(depositMsgsRemaining)) + + // next block, + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + // Reinitialize batch messages that were not executed in the previous batch and delete batch messages that were executed or ready to delete. + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + var depositMsgs3 []types.DepositMsgState + simapp.LiquidityKeeper.IterateAllDepositMsgStates(ctx, func(msg types.DepositMsgState) bool { + depositMsgs3 = append(depositMsgs3, msg) + return false + }) + require.Equal(t, 0, len(depositMsgs3)) + + var withdrawMsgs3 []types.WithdrawMsgState + simapp.LiquidityKeeper.IterateAllWithdrawMsgStates(ctx, func(msg types.WithdrawMsgState) bool { + withdrawMsgs3 = append(withdrawMsgs3, msg) + return false + }) + require.Equal(t, 0, len(withdrawMsgs3)) + + app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, yOfferCoins, yOrderPrices, yOrderAddrs, poolID, false) + app.TestSwapPool(t, simapp, ctx, offerCoins2, xOrderPrices, addrs[4:5], poolId2, false) + + swapMsgsPool1 := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStates(ctx, batch) + require.Equal(t, 4, len(swapMsgsPool1)) + + swapMsg, found := simapp.LiquidityKeeper.GetPoolBatchSwapMsgState(ctx, batch.PoolId, 1) + require.True(t, found) + require.Equal(t, swapMsg, swapMsgsPool1[0]) + + var swapMsgsAllPool []types.SwapMsgState + simapp.LiquidityKeeper.IterateAllSwapMsgStates(ctx, func(msg types.SwapMsgState) bool { + swapMsgsAllPool = append(swapMsgsAllPool, msg) + return false + }) + require.Equal(t, 5, len(swapMsgsAllPool)) + + swapMsgsAllPool = simapp.LiquidityKeeper.GetAllSwapMsgStates(ctx) + require.Equal(t, 5, len(swapMsgsAllPool)) + require.Equal(t, swapMsgsPool1, swapMsgsAllPool[:len(swapMsgsPool1)]) + + swapMsgsAllPool[1].Executed = true + simapp.LiquidityKeeper.SetPoolBatchSwapMsgStates(ctx, poolID, swapMsgsAllPool[1:2]) + + remainingSwapMsgs := simapp.LiquidityKeeper.GetAllRemainingPoolBatchSwapMsgStates(ctx, batch) + require.Equal(t, 1, len(remainingSwapMsgs)) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + // next block, + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + // Reinitialize batch messages that were not executed in the previous batch and delete batch messages that were executed or ready to delete. + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + var swapMsg2 []types.SwapMsgState + simapp.LiquidityKeeper.IterateAllSwapMsgStates(ctx, func(msg types.SwapMsgState) bool { + swapMsg2 = append(swapMsg2, msg) + return false + }) + require.Equal(t, 0, len(swapMsg2)) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + genesis := simapp.LiquidityKeeper.ExportGenesis(ctx) + simapp.LiquidityKeeper.InitGenesis(ctx, *genesis) + genesisNew := simapp.LiquidityKeeper.ExportGenesis(ctx) + require.Equal(t, genesis, genesisNew) + + simapp.LiquidityKeeper.DeletePoolBatch(ctx, batch) + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, batch.PoolId) + require.Equal(t, types.PoolBatch{}, batch) + require.False(t, found) +} diff --git a/x/liquidity/keeper/swap.go b/x/liquidity/keeper/swap.go new file mode 100644 index 00000000000..3d1dffd425b --- /dev/null +++ b/x/liquidity/keeper/swap.go @@ -0,0 +1,147 @@ +package keeper + +import ( + "fmt" + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// Execute Swap of the pool batch, Collect swap messages in batch for transact the same price for each batch and run them on endblock. +func (k Keeper) SwapExecution(ctx sdk.Context, poolBatch types.PoolBatch) (uint64, error) { + // get all swap message batch states that are not executed, not succeeded, and not to be deleted. + swapMsgStates := k.GetAllNotProcessedPoolBatchSwapMsgStates(ctx, poolBatch) + if len(swapMsgStates) == 0 { + return 0, nil + } + + pool, found := k.GetPool(ctx, poolBatch.PoolId) + if !found { + return 0, types.ErrPoolNotExists + } + + if k.IsDepletedPool(ctx, pool) { + return 0, types.ErrDepletedPool + } + + currentHeight := ctx.BlockHeight() + // set executed states of all messages to true + executedMsgCount := uint64(0) + var swapMsgStatesNotToBeDeleted []*types.SwapMsgState + for _, sms := range swapMsgStates { + sms.Executed = true + executedMsgCount++ + if currentHeight > sms.OrderExpiryHeight { + sms.ToBeDeleted = true + } + if err := k.ValidateMsgSwapWithinBatch(ctx, *sms.Msg, pool); err != nil { + sms.ToBeDeleted = true + } + if !sms.ToBeDeleted { + swapMsgStatesNotToBeDeleted = append(swapMsgStatesNotToBeDeleted, sms) + } else { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeSwapTransacted, + sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)), + sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(poolBatch.Index, 10)), + sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(sms.MsgIndex, 10)), + sdk.NewAttribute(types.AttributeValueSwapRequester, sms.Msg.GetSwapRequester().String()), + sdk.NewAttribute(types.AttributeValueSwapTypeId, strconv.FormatUint(uint64(sms.Msg.SwapTypeId), 10)), + sdk.NewAttribute(types.AttributeValueOfferCoinDenom, sms.Msg.OfferCoin.Denom), + sdk.NewAttribute(types.AttributeValueOfferCoinAmount, sms.Msg.OfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueDemandCoinDenom, sms.Msg.DemandCoinDenom), + sdk.NewAttribute(types.AttributeValueOrderPrice, sms.Msg.OrderPrice.String()), + sdk.NewAttribute(types.AttributeValueRemainingOfferCoinAmount, sms.RemainingOfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueExchangedOfferCoinAmount, sms.ExchangedOfferCoin.Amount.String()), + sdk.NewAttribute(types.AttributeValueReservedOfferCoinFeeAmount, sms.ReservedOfferCoinFee.Amount.String()), + sdk.NewAttribute(types.AttributeValueOrderExpiryHeight, strconv.FormatInt(sms.OrderExpiryHeight, 10)), + sdk.NewAttribute(types.AttributeValueSuccess, types.Failure), + )) + } + } + k.SetPoolBatchSwapMsgStatesByPointer(ctx, pool.Id, swapMsgStates) + swapMsgStates = swapMsgStatesNotToBeDeleted + + types.ValidateStateAndExpireOrders(swapMsgStates, currentHeight, false) + + // get reserve coins from the liquidity pool and calculate the current pool price (p = x / y) + reserveCoins := k.GetReserveCoins(ctx, pool) + + X := reserveCoins[0].Amount.ToDec() + Y := reserveCoins[1].Amount.ToDec() + currentPoolPrice := X.Quo(Y) + denomX := reserveCoins[0].Denom + denomY := reserveCoins[1].Denom + + // make orderMap, orderbook by sort orderMap + orderMap, xToY, yToX := types.MakeOrderMap(swapMsgStates, denomX, denomY, false) + orderBook := orderMap.SortOrderBook() + + // check orderbook validity and compute batchResult(direction, swapPrice, ..) + result, found := orderBook.Match(X, Y) + + if !found || X.Quo(Y).IsZero() { + err := k.RefundSwaps(ctx, pool, swapMsgStates) + return executedMsgCount, err + } + + // find order match, calculate pool delta with the total x, y amounts for the invariant check + var matchResultXtoY, matchResultYtoX []types.MatchResult + + poolXDelta := sdk.ZeroDec() + poolYDelta := sdk.ZeroDec() + + if result.MatchType != types.NoMatch { + var poolXDeltaXtoY, poolXDeltaYtoX, poolYDeltaYtoX, poolYDeltaXtoY sdk.Dec + matchResultXtoY, poolXDeltaXtoY, poolYDeltaXtoY = types.FindOrderMatch(types.DirectionXtoY, xToY, result.EX, result.SwapPrice, currentHeight) + matchResultYtoX, poolXDeltaYtoX, poolYDeltaYtoX = types.FindOrderMatch(types.DirectionYtoX, yToX, result.EY, result.SwapPrice, currentHeight) + poolXDelta = poolXDeltaXtoY.Add(poolXDeltaYtoX) + poolYDelta = poolYDeltaXtoY.Add(poolYDeltaYtoX) + } + + xToY, yToX, X, Y, poolXDelta2, poolYDelta2 := types.UpdateSwapMsgStates(X, Y, xToY, yToX, matchResultXtoY, matchResultYtoX) + + lastPrice := X.Quo(Y) + + if BatchLogicInvariantCheckFlag { + SwapMatchingInvariants(xToY, yToX, matchResultXtoY, matchResultYtoX) + SwapPriceInvariants(matchResultXtoY, matchResultYtoX, poolXDelta, poolYDelta, poolXDelta2, poolYDelta2, result) + } + + types.ValidateStateAndExpireOrders(xToY, currentHeight, false) + types.ValidateStateAndExpireOrders(yToX, currentHeight, false) + + orderMapExecuted, _, _ := types.MakeOrderMap(append(xToY, yToX...), denomX, denomY, true) + orderBookExecuted := orderMapExecuted.SortOrderBook() + if !orderBookExecuted.Validate(lastPrice) { + return executedMsgCount, types.ErrOrderBookInvalidity + } + + types.ValidateStateAndExpireOrders(xToY, currentHeight, true) + types.ValidateStateAndExpireOrders(yToX, currentHeight, true) + + // make index map for match result + matchResultMap := make(map[uint64]types.MatchResult) + for _, match := range append(matchResultXtoY, matchResultYtoX...) { + if _, ok := matchResultMap[match.SwapMsgState.MsgIndex]; ok { + return executedMsgCount, fmt.Errorf("duplicate match order") + } + matchResultMap[match.SwapMsgState.MsgIndex] = match + } + + if BatchLogicInvariantCheckFlag { + SwapPriceDirectionInvariants(currentPoolPrice, result) + SwapMsgStatesInvariants(matchResultXtoY, matchResultYtoX, matchResultMap, swapMsgStates, xToY, yToX) + SwapOrdersExecutionStateInvariants(matchResultMap, swapMsgStates, result, denomX) + } + + // execute transact, refund, expire, send coins with escrow, update state by TransactAndRefundSwapLiquidityPool + if err := k.TransactAndRefundSwapLiquidityPool(ctx, swapMsgStates, matchResultMap, pool, result); err != nil { + return executedMsgCount, err + } + + return executedMsgCount, nil +} diff --git a/x/liquidity/keeper/swap_test.go b/x/liquidity/keeper/swap_test.go new file mode 100644 index 00000000000..654da75a377 --- /dev/null +++ b/x/liquidity/keeper/swap_test.go @@ -0,0 +1,357 @@ +package keeper_test + +import ( + "math/rand" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestSimulationSwapExecutionFindEdgeCase(t *testing.T) { + for seed := int64(0); seed < 20; seed++ { + r := rand.New(rand.NewSource(seed)) + + simapp, ctx := createTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + // define test denom X, Y for Liquidity Pool + denomX := "denomX" + denomY := "denomY" + denomX, denomY = types.AlphabeticalDenomPair(denomX, denomY) + + // get random X, Y amount for create pool + param := simapp.LiquidityKeeper.GetParams(ctx) + X, Y := app.GetRandPoolAmt(r, param.MinInitDepositAmount) + deposit := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) + + // set pool creator account, balance for deposit + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + app.SaveAccount(simapp, ctx, addrs[0], deposit) // pool creator + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomX) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomY) + depositBalance := sdk.NewCoins(depositA, depositB) + require.Equal(t, deposit, depositBalance) + + // create Liquidity pool + poolTypeID := types.DefaultPoolTypeID + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + for i := 0; i < 20; i++ { + ctx = ctx.WithBlockHeight(int64(i)) + testSwapEdgeCases(t, r, simapp, ctx, X, Y, depositBalance, addrs) + } + } +} + +func TestSwapExecution(t *testing.T) { + for seed := int64(0); seed < 50; seed++ { + s := rand.NewSource(seed) + r := rand.New(s) + simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + // define test denom X, Y for Liquidity Pool + denomX := "denomX" + denomY := "denomY" + denomX, denomY = types.AlphabeticalDenomPair(denomX, denomY) + + // get random X, Y amount for create pool + X, Y := app.GetRandPoolAmt(r, params.MinInitDepositAmount) + deposit := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) + + // set pool creator account, balance for deposit + addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) + app.SaveAccount(simapp, ctx, addrs[0], deposit) // pool creator + depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomX) + depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomY) + depositBalance := sdk.NewCoins(depositA, depositB) + require.Equal(t, deposit, depositBalance) + + // create Liquidity pool + poolTypeID := types.DefaultPoolTypeID + msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + // verify created liquidity pool + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + poolID := pools[0].Id + require.Equal(t, 1, len(pools)) + require.Equal(t, uint64(1), poolID) + require.Equal(t, denomX, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomY, pools[0].ReserveCoinDenoms[1]) + + // verify minted pool coin + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + var xToY []*types.MsgSwapWithinBatch // buying Y from X + var yToX []*types.MsgSwapWithinBatch // selling Y for X + + // make random orders, set buyer, seller accounts for the orders + xToY, yToX = app.GetRandomSizeOrders(denomX, denomY, X, Y, r, 250, 250) + buyerAddrs := app.AddTestAddrsIncremental(simapp, ctx, len(xToY), sdk.NewInt(0)) + sellerAddrs := app.AddTestAddrsIncremental(simapp, ctx, len(yToX), sdk.NewInt(0)) + + for i, msg := range xToY { + app.SaveAccountWithFee(simapp, ctx, buyerAddrs[i], sdk.NewCoins(msg.OfferCoin), msg.OfferCoin) + msg.SwapRequesterAddress = buyerAddrs[i].String() + msg.PoolId = poolID + msg.OfferCoinFee = types.GetOfferCoinFee(msg.OfferCoin, params.SwapFeeRate) + } + for i, msg := range yToX { + app.SaveAccountWithFee(simapp, ctx, sellerAddrs[i], sdk.NewCoins(msg.OfferCoin), msg.OfferCoin) + msg.SwapRequesterAddress = sellerAddrs[i].String() + msg.PoolId = poolID + msg.OfferCoinFee = types.GetOfferCoinFee(msg.OfferCoin, params.SwapFeeRate) + } + + // begin block, delete and init pool batch + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // handle msgs, set order msgs to batch + for _, msg := range xToY { + _, err := simapp.LiquidityKeeper.SwapWithinBatch(ctx, msg, 0) + require.NoError(t, err) + } + for _, msg := range yToX { + _, err := simapp.LiquidityKeeper.SwapWithinBatch(ctx, msg, 0) + require.NoError(t, err) + } + + // verify pool batch + liquidityPoolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + require.NotNil(t, liquidityPoolBatch) + + // end block, swap execution + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + } +} + +func testSwapEdgeCases(t *testing.T, r *rand.Rand, simapp *app.LiquidityApp, ctx sdk.Context, X, Y sdk.Int, depositBalance sdk.Coins, addrs []sdk.AccAddress) { + // simapp, ctx := createTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + denomX := depositBalance[0].Denom + denomY := depositBalance[1].Denom + + // verify created liquidity pool + pools := simapp.LiquidityKeeper.GetAllPools(ctx) + poolID := pools[0].Id + require.Equal(t, 1, len(pools)) + require.Equal(t, uint64(1), poolID) + require.Equal(t, denomX, pools[0].ReserveCoinDenoms[0]) + require.Equal(t, denomY, pools[0].ReserveCoinDenoms[1]) + + // verify minted pool coin + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + + var xToY []*types.MsgSwapWithinBatch // buying Y from X + var yToX []*types.MsgSwapWithinBatch // selling Y for X + + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + + remainingSwapMsgs := simapp.LiquidityKeeper.GetAllNotProcessedPoolBatchSwapMsgStates(ctx, batch) + if ctx.BlockHeight() == 0 || len(remainingSwapMsgs) == 0 { + // make random orders, set buyer, seller accounts for the orders + xToY, yToX = app.GetRandomSizeOrders(denomX, denomY, X, Y, r, 100, 100) + buyerAddrs := app.AddTestAddrsIncremental(simapp, ctx, len(xToY), sdk.NewInt(0)) + sellerAddrs := app.AddTestAddrsIncremental(simapp, ctx, len(yToX), sdk.NewInt(0)) + + for i, msg := range xToY { + app.SaveAccountWithFee(simapp, ctx, buyerAddrs[i], sdk.NewCoins(msg.OfferCoin), msg.OfferCoin) + msg.SwapRequesterAddress = buyerAddrs[i].String() + msg.PoolId = poolID + msg.OfferCoinFee = types.GetOfferCoinFee(msg.OfferCoin, params.SwapFeeRate) + } + for i, msg := range yToX { + app.SaveAccountWithFee(simapp, ctx, sellerAddrs[i], sdk.NewCoins(msg.OfferCoin), msg.OfferCoin) + msg.SwapRequesterAddress = sellerAddrs[i].String() + msg.PoolId = poolID + msg.OfferCoinFee = types.GetOfferCoinFee(msg.OfferCoin, params.SwapFeeRate) + } + } + + // begin block, delete and init pool batch + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // handle msgs, set order msgs to batch + for _, msg := range xToY { + _, err := simapp.LiquidityKeeper.SwapWithinBatch(ctx, msg, int64(r.Intn(4))) + require.NoError(t, err) + } + for _, msg := range yToX { + _, err := simapp.LiquidityKeeper.SwapWithinBatch(ctx, msg, int64(r.Intn(4))) + require.NoError(t, err) + } + + // verify pool batch + liquidityPoolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + require.NotNil(t, liquidityPoolBatch) + + // end block, swap execution + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) +} + +func TestBadSwapExecution(t *testing.T) { + r := rand.New(rand.NewSource(0)) + + simapp, ctx := app.CreateTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + denomX, denomY := types.AlphabeticalDenomPair("denomX", "denomY") + + // add pool creator account + X, Y := app.GetRandPoolAmt(r, params.MinInitDepositAmount) + deposit := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) + creatorAddr := app.AddRandomTestAddr(simapp, ctx, deposit.Add(params.PoolCreationFee...)) + balanceX := simapp.BankKeeper.GetBalance(ctx, creatorAddr, denomX) + balanceY := simapp.BankKeeper.GetBalance(ctx, creatorAddr, denomY) + creatorBalance := sdk.NewCoins(balanceX, balanceY) + require.Equal(t, deposit, creatorBalance) + + // create pool + createPoolMsg := types.NewMsgCreatePool(creatorAddr, types.DefaultPoolTypeID, creatorBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, createPoolMsg) + require.NoError(t, err) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + offerCoin := sdk.NewCoin(denomX, sdk.NewInt(10000)) + offerCoinFee := types.GetOfferCoinFee(offerCoin, params.SwapFeeRate) + testAddr := app.AddRandomTestAddr(simapp, ctx, sdk.NewCoins(offerCoin.Add(offerCoinFee))) + + currentPrice := X.ToDec().Quo(Y.ToDec()) + swapMsg := types.NewMsgSwapWithinBatch(testAddr, 0, types.DefaultSwapTypeID, offerCoin, denomY, currentPrice, params.SwapFeeRate) + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, swapMsg, 0) + require.ErrorIs(t, err, types.ErrPoolNotExists) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) +} + +func TestBalancesAfterSwap(t *testing.T) { + for price := int64(9800); price < 10000; price++ { + simapp, ctx := app.CreateTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + denomX, denomY := types.AlphabeticalDenomPair("denomx", "denomy") + X, Y := sdk.NewInt(100_000_000), sdk.NewInt(100_000_000) + + creatorCoins := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) + creatorAddr := app.AddRandomTestAddr(simapp, ctx, creatorCoins.Add(params.PoolCreationFee...)) + + orderPrice := sdk.NewDecWithPrec(price, 4) + aliceCoin := sdk.NewCoin(denomY, sdk.NewInt(10_000_000)) + aliceAddr := app.AddRandomTestAddr(simapp, ctx, sdk.NewCoins(aliceCoin)) + + pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creatorAddr, types.DefaultPoolTypeID, creatorCoins)) + require.NoError(t, err) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + offerAmt := aliceCoin.Amount.ToDec().Quo(sdk.MustNewDecFromStr("1.0015")).TruncateInt() + offerCoin := sdk.NewCoin(denomY, offerAmt) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, types.NewMsgSwapWithinBatch( + aliceAddr, pool.Id, types.DefaultSwapTypeID, offerCoin, denomX, orderPrice, params.SwapFeeRate), 0) + require.NoError(t, err) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + deltaX := simapp.BankKeeper.GetBalance(ctx, aliceAddr, denomX).Amount + deltaY := simapp.BankKeeper.GetBalance(ctx, aliceAddr, denomY).Amount.Sub(aliceCoin.Amount) + require.Truef(t, !deltaX.IsNegative(), "deltaX should not be negative: %s", deltaX) + require.Truef(t, deltaY.IsNegative(), "deltaY should be negative: %s", deltaY) + + deltaXWithoutFee := deltaX.ToDec().Quo(sdk.MustNewDecFromStr("0.9985")) + deltaYWithoutFee := deltaY.ToDec().Quo(sdk.MustNewDecFromStr("1.0015")) + effectivePrice := deltaXWithoutFee.Quo(deltaYWithoutFee.Neg()) + priceDiffRatio := orderPrice.Sub(effectivePrice).Abs().Quo(orderPrice) + require.Truef(t, priceDiffRatio.LT(sdk.MustNewDecFromStr("0.01")), "effectivePrice differs too much from orderPrice") + } +} + +func TestRefundEscrow(t *testing.T) { + for seed := int64(0); seed < 100; seed++ { + r := rand.New(rand.NewSource(seed)) + + X := sdk.NewInt(1_000_000) + Y := app.GetRandRange(r, 10_000_000_000_000_000, 1_000_000_000_000_000_000) + + simapp, ctx := createTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + addr := app.AddRandomTestAddr(simapp, ctx, sdk.NewCoins()) + + pool, err := createPool(simapp, ctx, X, Y, DenomX, DenomY) + require.NoError(t, err) + + for i := 0; i < 100; i++ { + poolBalances := simapp.BankKeeper.GetAllBalances(ctx, pool.GetReserveAccount()) + RX := poolBalances.AmountOf(DenomX) + RY := poolBalances.AmountOf(DenomY) + poolPrice := RX.ToDec().Quo(RY.ToDec()) + + offerAmt := RY.ToDec().Mul(sdk.NewDecFromIntWithPrec(app.GetRandRange(r, 1, 100_000_000_000_000_000), sdk.Precision)) // RY * (0, 0.1) + offerAmtWithFee := offerAmt.Quo(sdk.OneDec().Add(params.SwapFeeRate.QuoInt64(2))).TruncateInt() // offerAmt / (1 + swapFeeRate/2) + orderPrice := poolPrice.Mul(sdk.NewDecFromIntWithPrec(app.GetRandRange(r, 1, 1_000_000_000_000_000_000), sdk.Precision)) // poolPrice * (0, 1) + + app.SaveAccount(simapp, ctx, addr, sdk.NewCoins(sdk.NewCoin(DenomY, offerAmt.Ceil().TruncateInt()))) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + _, err := simapp.LiquidityKeeper.SwapWithinBatch(ctx, types.NewMsgSwapWithinBatch( + addr, pool.Id, types.DefaultSwapTypeID, sdk.NewCoin(DenomY, offerAmtWithFee), DenomX, orderPrice, params.SwapFeeRate), 0) + require.NoError(t, err) + + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + } + + require.True(t, simapp.BankKeeper.GetAllBalances(ctx, simapp.AccountKeeper.GetModuleAddress(types.ModuleName)).IsZero(), "there must be no remaining coin escrow") + } +} + +func TestSwapWithDepletedPool(t *testing.T) { + simapp, ctx, pool, creatorAddr, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1000000)) + require.NoError(t, err) + params := simapp.LiquidityKeeper.GetParams(ctx) + + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + pc := simapp.BankKeeper.GetBalance(ctx, creatorAddr, pool.PoolCoinDenom) + _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, pc)) + require.NoError(t, err) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + addr := app.AddRandomTestAddr(simapp, ctx, sdk.NewCoins(sdk.NewInt64Coin(DenomX, 100000))) + offerCoin := sdk.NewInt64Coin(DenomX, 10000) + orderPrice := sdk.MustNewDecFromStr("1.0") + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + _, err = simapp.LiquidityKeeper.SwapWithinBatch( + ctx, + types.NewMsgSwapWithinBatch(addr, pool.Id, types.DefaultSwapTypeID, offerCoin, DenomY, orderPrice, params.SwapFeeRate), + 0) + require.ErrorIs(t, err, types.ErrDepletedPool) + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) +} + +func createPool(simapp *app.LiquidityApp, ctx sdk.Context, X, Y sdk.Int, denomX, denomY string) (types.Pool, error) { + params := simapp.LiquidityKeeper.GetParams(ctx) + + coins := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) + addr := app.AddRandomTestAddr(simapp, ctx, coins.Add(params.PoolCreationFee...)) + + return simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(addr, types.DefaultPoolTypeID, coins)) +} diff --git a/x/liquidity/legacy/v042/keys.go b/x/liquidity/legacy/v042/keys.go new file mode 100644 index 00000000000..0e7286c48eb --- /dev/null +++ b/x/liquidity/legacy/v042/keys.go @@ -0,0 +1,32 @@ +// Package v042 is copy-pasted from: +// https://github.com/tendermint/liquidity/blob/v1.2.9/x/liquidity/types/keys.go +package v042 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // ModuleName is the name of the liquidity module + ModuleName = "liquidity" +) + +var ( + PoolByReserveAccIndexKeyPrefix = []byte{0x12} + + PoolBatchIndexKeyPrefix = []byte{0x21} // Last PoolBatchIndex +) + +// - PoolByReserveAccIndex: `0x12 | ReserveAcc -> Id` +// GetPoolByReserveAccIndexKey returns kv indexing key of the pool indexed by reserve account +func GetPoolByReserveAccIndexKey(reserveAcc sdk.AccAddress) []byte { + return append(PoolByReserveAccIndexKeyPrefix, reserveAcc.Bytes()...) +} + +// GetPoolBatchIndexKey returns kv indexing key of the latest index value of the pool batch +func GetPoolBatchIndexKey(poolID uint64) []byte { + key := make([]byte, 9) + key[0] = PoolBatchIndexKeyPrefix[0] + copy(key[1:9], sdk.Uint64ToBigEndian(poolID)) + return key +} diff --git a/x/liquidity/legacy/v043/helpers.go b/x/liquidity/legacy/v043/helpers.go new file mode 100644 index 00000000000..f9b49461cbe --- /dev/null +++ b/x/liquidity/legacy/v043/helpers.go @@ -0,0 +1,36 @@ +package v043 + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" +) + +// MigratePrefixAddress is a helper function that migrates all keys of format: +// prefix_bytes | address_bytes +// into format: +// prefix_bytes | address_len (1 byte) | address_bytes +func MigratePrefixAddress(store sdk.KVStore, prefixBz []byte) { + oldStore := prefix.NewStore(store, prefixBz) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + // Set new key on store. Values don't change. + store.Set(append(prefixBz, address.MustLengthPrefix(oldStoreIter.Key())...), oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} + +// DeleteDeprecatedPrefix is a helper function that deletes all keys which started the prefix +func DeleteDeprecatedPrefix(store sdk.KVStore, prefixBz []byte) { + oldStore := prefix.NewStore(store, prefixBz) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + oldStore.Delete(oldStoreIter.Key()) + } +} diff --git a/x/liquidity/legacy/v043/store.go b/x/liquidity/legacy/v043/store.go new file mode 100644 index 00000000000..7b856b1ecd5 --- /dev/null +++ b/x/liquidity/legacy/v043/store.go @@ -0,0 +1,25 @@ +package v043 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + v042liquidity "github.com/cosmos/gaia/v9/x/liquidity/legacy/v042" +) + +// MigrateStore performs in-place store migrations from v0.42 to v0.43. The +// migration includes: +// +// - Change addresses to be length-prefixed. +func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error { + store := ctx.KVStore(storeKey) + + // old key format v042: + // PoolByReserveAccIndex: `0x12 | ReserveAcc -> ProtocolBuffer(uint64)` + // PoolBatchIndex: `0x21 | PoolId -> ProtocolBuffer(uint64)` + // new key format v043: + // PoolByReserveAccIndex: `0x12 | ReserveAccLen (1 byte) | ReserveAcc -> ProtocolBuffer(uint64)` + // PoolBatchIndex: deprecated + MigratePrefixAddress(store, v042liquidity.PoolByReserveAccIndexKeyPrefix) + DeleteDeprecatedPrefix(store, v042liquidity.PoolBatchIndexKeyPrefix) + return nil +} diff --git a/x/liquidity/legacy/v043/store_test.go b/x/liquidity/legacy/v043/store_test.go new file mode 100644 index 00000000000..59a0dc0a2e4 --- /dev/null +++ b/x/liquidity/legacy/v043/store_test.go @@ -0,0 +1,81 @@ +package v043_test + +import ( + "bytes" + "testing" + + "github.com/cosmos/cosmos-sdk/simapp" + gogotypes "github.com/gogo/protobuf/types" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + + v042liquidity "github.com/cosmos/gaia/v9/x/liquidity/legacy/v042" + v043liquidity "github.com/cosmos/gaia/v9/x/liquidity/legacy/v043" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestStoreMigration(t *testing.T) { + encCfg := simapp.MakeTestEncodingConfig() + liquidityKey := sdk.NewKVStoreKey(v042liquidity.ModuleName) + ctx := testutil.DefaultContext(liquidityKey, sdk.NewTransientStoreKey("transient_test")) + store := ctx.KVStore(liquidityKey) + + _, _, reserveAcc1 := testdata.KeyTestPubAddr() + _, _, reserveAcc2 := testdata.KeyTestPubAddr() + + // Use dummy value for all keys. + value := encCfg.Marshaler.MustMarshal(&gogotypes.UInt64Value{Value: 1}) + + testCases := []struct { + name string + oldKey []byte + newKey []byte + }{ + { + "reserveAcc1", + v042liquidity.GetPoolByReserveAccIndexKey(reserveAcc1), + types.GetPoolByReserveAccIndexKey(reserveAcc1), + }, + { + "reserveAcc2", + v042liquidity.GetPoolByReserveAccIndexKey(reserveAcc2), + types.GetPoolByReserveAccIndexKey(reserveAcc2), + }, + { + "poolBatchIndexKeyPrefix1", + v042liquidity.GetPoolBatchIndexKey(1), + nil, + }, + { + "poolBatchIndexKeyPrefix2", + v042liquidity.GetPoolBatchIndexKey(2), + nil, + }, + } + + // Set all the old keys to the store + for _, tc := range testCases { + store.Set(tc.oldKey, value) + } + + // Run migrations. + err := v043liquidity.MigrateStore(ctx, liquidityKey) + require.NoError(t, err) + + // Make sure the new keys are set and old keys are deleted. + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + if !bytes.Equal(tc.oldKey, tc.newKey) { + require.Nil(t, store.Get(tc.oldKey)) + } + if tc.newKey != nil { + require.Equal(t, value, store.Get(tc.newKey)) + } + }) + } +} diff --git a/x/liquidity/module.go b/x/liquidity/module.go new file mode 100644 index 00000000000..577372b1895 --- /dev/null +++ b/x/liquidity/module.go @@ -0,0 +1,205 @@ +package liquidity + +// DONTCOVER + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + + sdkclient "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "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/gaia/v9/x/liquidity/client/cli" + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/simulation" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleSimulation = AppModule{} +) + +// AppModuleBasic defines the basic application module used by the liquidity module. +type AppModuleBasic struct { + cdc codec.Codec +} + +// Name returns the liquidity module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the gov module's types for the given codec. +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +// DefaultGenesis returns default genesis state as raw bytes for the liquidity module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesisState()) +} + +// ValidateGenesis performs genesis state validation for the liquidity module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config sdkclient.TxEncodingConfig, bz json.RawMessage) error { + var data types.GenesisState + if err := cdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + + return types.ValidateGenesis(data) +} + +// RegisterRESTRoutes registers the REST routes for the liquidity module. +func (AppModuleBasic) RegisterRESTRoutes(clientCtx sdkclient.Context, rtr *mux.Router) { +} + +// GetTxCmd returns the root tx command for the liquidity module. +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns no root query command for the liquidity module. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// RegisterInterfaces implements InterfaceModule.RegisterInterfaces +func (a AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the liquidity module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux *runtime.ServeMux) { + types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) +} + +// RegisterServices registers module services. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + querier := keeper.Querier{Keeper: am.keeper} + types.RegisterQueryServer(cfg.QueryServer(), querier) + m := keeper.NewMigrator(am.keeper) + cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2) +} + +// AppModule implements an application module for the liquidity module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + distrKeeper types.DistributionKeeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper, dk types.DistributionKeeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{cdc: cdc}, + keeper: keeper, + accountKeeper: ak, + bankKeeper: bk, + distrKeeper: dk, + } +} + +// Name returns the liquidity module's name. +func (AppModule) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the gov module's types for the given codec. +func (AppModule) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +// RegisterInvariants registers the liquidity module invariants. +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + keeper.RegisterInvariants(ir, am.keeper) +} + +// Route returns the message routing key for the liquidity module. +func (am AppModule) Route() sdk.Route { + return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) +} + +// QuerierRoute returns the liquidity module's querier route name. +func (AppModule) QuerierRoute() string { + return types.QuerierRoute +} + +// LegacyQuerierHandler returns the liquidity module sdk.Querier. +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return keeper.NewQuerier(am.keeper, legacyQuerierCdc) +} + +// InitGenesis performs genesis initialization for the liquidity module. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + cdc.MustUnmarshalJSON(data, &genesisState) + InitGenesis(ctx, am.keeper, genesisState) + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the exported genesis state as raw bytes for the liquidity module. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(gs) +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 2 } + +// BeginBlock performs a no-op. +func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { + BeginBlocker(ctx, am.keeper) +} + +// EndBlock returns the end blocker for the liquidity module. It returns no validator updates. +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + EndBlocker(ctx, am.keeper) + return []abci.ValidatorUpdate{} +} + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the liquidity module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized liquidity param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for liquidity module's types +func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc) +} + +// WeightedOperations returns the all the liquidity module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, + am.accountKeeper, am.bankKeeper, am.keeper, + ) +} diff --git a/x/liquidity/module_test.go b/x/liquidity/module_test.go new file mode 100644 index 00000000000..1c7b5bbc52b --- /dev/null +++ b/x/liquidity/module_test.go @@ -0,0 +1,25 @@ +package liquidity_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + abcitypes "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + lapp "github.com/cosmos/gaia/v9/app" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := lapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + + app.InitChain( + abcitypes.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + params := app.LiquidityKeeper.GetParams(ctx) + require.NotNil(t, params) +} diff --git a/x/liquidity/simulation/decoder.go b/x/liquidity/simulation/decoder.go new file mode 100644 index 00000000000..cfb6042169a --- /dev/null +++ b/x/liquidity/simulation/decoder.go @@ -0,0 +1,56 @@ +package simulation + +import ( + "bytes" + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/kv" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's +// Value to the corresponding liquidity type. +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { + return func(kvA, kvB kv.Pair) string { + switch { + case bytes.Equal(kvA.Key[:1], types.PoolKeyPrefix): + var poolA, poolB types.Pool + cdc.MustUnmarshal(kvA.Value, &poolA) + cdc.MustUnmarshal(kvB.Value, &poolB) + return fmt.Sprintf("%v\n%v", poolA, poolB) + + case bytes.Equal(kvA.Key[:1], types.PoolByReserveAccIndexKeyPrefix): + return fmt.Sprintf("%v\n%v", sdk.AccAddress(kvA.Value), sdk.AccAddress(kvB.Value)) + + case bytes.Equal(kvA.Key[:1], types.PoolBatchKeyPrefix): + var batchA, batchB types.PoolBatch + cdc.MustUnmarshal(kvA.Value, &batchA) + cdc.MustUnmarshal(kvB.Value, &batchB) + return fmt.Sprintf("%v\n%v", batchA, batchB) + + case bytes.Equal(kvA.Key[:1], types.PoolBatchDepositMsgStateIndexKeyPrefix): + var msgStateA, msgStateB types.DepositMsgState + cdc.MustUnmarshal(kvA.Value, &msgStateA) + cdc.MustUnmarshal(kvB.Value, &msgStateB) + return fmt.Sprintf("%v\n%v", msgStateA, msgStateB) + + case bytes.Equal(kvA.Key[:1], types.PoolBatchWithdrawMsgStateIndexKeyPrefix): + var msgStateA, msgStateB types.WithdrawMsgState + cdc.MustUnmarshal(kvA.Value, &msgStateA) + cdc.MustUnmarshal(kvB.Value, &msgStateB) + return fmt.Sprintf("%v\n%v", msgStateA, msgStateB) + + case bytes.Equal(kvA.Key[:1], types.PoolBatchSwapMsgStateIndexKeyPrefix): + var msgStateA, msgStateB types.SwapMsgState + cdc.MustUnmarshal(kvA.Value, &msgStateA) + cdc.MustUnmarshal(kvB.Value, &msgStateB) + return fmt.Sprintf("%v\n%v", msgStateA, msgStateB) + + default: + panic(fmt.Sprintf("invalid liquidity key prefix %X", kvA.Key[:1])) + } + } +} diff --git a/x/liquidity/simulation/decoder_test.go b/x/liquidity/simulation/decoder_test.go new file mode 100644 index 00000000000..0823933354a --- /dev/null +++ b/x/liquidity/simulation/decoder_test.go @@ -0,0 +1,98 @@ +package simulation_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/kv" + + "github.com/cosmos/gaia/v9/x/liquidity/simulation" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +var ( + pk1 = ed25519.GenPrivKey().PubKey() + reserveAccAddr1 = sdk.AccAddress(pk1.Address()) + reserveCoinDenoms = []string{"dzkiv", "imwo"} + poolName = types.PoolName(reserveCoinDenoms, uint32(1)) + poolCoinDenom = types.GetPoolCoinDenom(poolName) +) + +func TestDecodeLiquidityStore(t *testing.T) { + cdc := simapp.MakeTestEncodingConfig().Marshaler + dec := simulation.NewDecodeStore(cdc) + + pool := types.Pool{ + Id: uint64(1), + TypeId: uint32(1), + ReserveCoinDenoms: reserveCoinDenoms, + ReserveAccountAddress: reserveAccAddr1.String(), + PoolCoinDenom: poolCoinDenom, + } + batch := types.NewPoolBatch(1, 1) + depositMsgState := types.DepositMsgState{ + MsgHeight: int64(50), + MsgIndex: uint64(1), + Executed: true, + Succeeded: true, + ToBeDeleted: true, + Msg: &types.MsgDepositWithinBatch{PoolId: uint64(1)}, + } + withdrawMsgState := types.WithdrawMsgState{ + MsgHeight: int64(50), + MsgIndex: uint64(1), + Executed: true, + Succeeded: true, + ToBeDeleted: true, + Msg: &types.MsgWithdrawWithinBatch{PoolId: uint64(1)}, + } + swapMsgState := types.SwapMsgState{ + MsgHeight: int64(50), + MsgIndex: uint64(1), + Executed: true, + Succeeded: true, + ToBeDeleted: true, + Msg: &types.MsgSwapWithinBatch{PoolId: uint64(1)}, + } + + kvPairs := kv.Pairs{ + Pairs: []kv.Pair{ + {Key: types.PoolKeyPrefix, Value: cdc.MustMarshal(&pool)}, + {Key: types.PoolByReserveAccIndexKeyPrefix, Value: reserveAccAddr1.Bytes()}, + {Key: types.PoolBatchKeyPrefix, Value: cdc.MustMarshal(&batch)}, + {Key: types.PoolBatchDepositMsgStateIndexKeyPrefix, Value: cdc.MustMarshal(&depositMsgState)}, + {Key: types.PoolBatchWithdrawMsgStateIndexKeyPrefix, Value: cdc.MustMarshal(&withdrawMsgState)}, + {Key: types.PoolBatchSwapMsgStateIndexKeyPrefix, Value: cdc.MustMarshal(&swapMsgState)}, + {Key: []byte{0x99}, Value: []byte{0x99}}, + }, + } + + tests := []struct { + name string + expectedLog string + }{ + {"Pool", fmt.Sprintf("%v\n%v", pool, pool)}, + {"PoolByReserveAccIndex", fmt.Sprintf("%v\n%v", reserveAccAddr1, reserveAccAddr1)}, + {"PoolBatchKey", fmt.Sprintf("%v\n%v", batch, batch)}, + {"PoolBatchDepositMsgStateIndex", fmt.Sprintf("%v\n%v", depositMsgState, depositMsgState)}, + {"PoolBatchWithdrawMsgStateIndex", fmt.Sprintf("%v\n%v", withdrawMsgState, withdrawMsgState)}, + {"PoolBatchSwapMsgStateIndex", fmt.Sprintf("%v\n%v", swapMsgState, swapMsgState)}, + {"other", ""}, + } + for i, tt := range tests { + i, tt := i, tt + t.Run(tt.name, func(t *testing.T) { + switch i { + case len(tests) - 1: + require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name) + default: + require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name) + } + }) + } +} diff --git a/x/liquidity/simulation/genesis.go b/x/liquidity/simulation/genesis.go new file mode 100644 index 00000000000..f2fa467ec8b --- /dev/null +++ b/x/liquidity/simulation/genesis.go @@ -0,0 +1,167 @@ +package simulation + +// DONTCOVER + +import ( + "encoding/json" + "fmt" + "math/rand" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/types/simulation" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// Simulation parameter constants +const ( + LiquidityPoolTypes = "liquidity_pool_types" + MinInitDepositAmount = "min_init_deposit_amount" + InitPoolCoinMintAmount = "init_pool_coin_mint_amount" + MaxReserveCoinAmount = "max_reserve_coin_amount" + PoolCreationFee = "pool_creation_fee" + SwapFeeRate = "swap_fee_rate" + WithdrawFeeRate = "withdraw_fee_rate" + MaxOrderAmountRatio = "max_order_amount_ratio" + UnitBatchHeight = "unit_batch_height" +) + +// GenLiquidityPoolTypes return default PoolType temporarily, It will be randomized in the liquidity v2 +func GenLiquidityPoolTypes(r *rand.Rand) (liquidityPoolTypes []types.PoolType) { + return types.DefaultPoolTypes +} + +// GenMinInitDepositAmount randomized MinInitDepositAmount +func GenMinInitDepositAmount(r *rand.Rand) sdk.Int { + return sdk.NewInt(int64(simulation.RandIntBetween(r, int(types.DefaultMinInitDepositAmount.Int64()), 1e7))) +} + +// GenInitPoolCoinMintAmount randomized InitPoolCoinMintAmount +func GenInitPoolCoinMintAmount(r *rand.Rand) sdk.Int { + return sdk.NewInt(int64(simulation.RandIntBetween(r, int(types.DefaultInitPoolCoinMintAmount.Int64()), 1e8))) +} + +// GenMaxReserveCoinAmount randomized MaxReserveCoinAmount +func GenMaxReserveCoinAmount(r *rand.Rand) sdk.Int { + return sdk.NewInt(int64(simulation.RandIntBetween(r, int(types.DefaultMaxReserveCoinAmount.Int64()), 1e13))) +} + +// GenPoolCreationFee randomized PoolCreationFee +// list of 1 to 4 coins with an amount greater than 1 +func GenPoolCreationFee(r *rand.Rand) sdk.Coins { + var coins sdk.Coins + var denoms []string + + count := simulation.RandIntBetween(r, 1, 4) + for i := 0; i < count; i++ { + randomDenom := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 4, 6)) + denoms = append(denoms, strings.ToLower(randomDenom)) + } + + sortedDenoms := types.SortDenoms(denoms) + + for i := 0; i < count; i++ { + randomCoin := sdk.NewCoin(sortedDenoms[i], sdk.NewInt(int64(simulation.RandIntBetween(r, 1e6, 1e7)))) + coins = append(coins, randomCoin) + } + + return coins +} + +// GenSwapFeeRate randomized SwapFeeRate ranging from 0.00001 to 1 +func GenSwapFeeRate(r *rand.Rand) sdk.Dec { + return sdk.NewDecWithPrec(int64(simulation.RandIntBetween(r, 1, 1e5)), 5) +} + +// GenWithdrawFeeRate randomized WithdrawFeeRate ranging from 0.00001 to 1 +func GenWithdrawFeeRate(r *rand.Rand) sdk.Dec { + return sdk.NewDecWithPrec(int64(simulation.RandIntBetween(r, 1, 1e5)), 5) +} + +// GenMaxOrderAmountRatio randomized MaxOrderAmountRatio ranging from 0.00001 to 1 +func GenMaxOrderAmountRatio(r *rand.Rand) sdk.Dec { + return sdk.NewDecWithPrec(int64(simulation.RandIntBetween(r, 1, 1e5)), 5) +} + +// GenUnitBatchHeight randomized UnitBatchHeight ranging from 1 to 20 +func GenUnitBatchHeight(r *rand.Rand) uint32 { + return uint32(simulation.RandIntBetween(r, int(types.DefaultUnitBatchHeight), 20)) +} + +// RandomizedGenState generates a random GenesisState for liquidity +func RandomizedGenState(simState *module.SimulationState) { + var liquidityPoolTypes []types.PoolType + simState.AppParams.GetOrGenerate( + simState.Cdc, LiquidityPoolTypes, &liquidityPoolTypes, simState.Rand, + func(r *rand.Rand) { liquidityPoolTypes = GenLiquidityPoolTypes(r) }, + ) + + var minInitDepositAmount sdk.Int + simState.AppParams.GetOrGenerate( + simState.Cdc, MinInitDepositAmount, &minInitDepositAmount, simState.Rand, + func(r *rand.Rand) { minInitDepositAmount = GenMinInitDepositAmount(r) }, + ) + + var initPoolCoinMintAmount sdk.Int + simState.AppParams.GetOrGenerate( + simState.Cdc, InitPoolCoinMintAmount, &initPoolCoinMintAmount, simState.Rand, + func(r *rand.Rand) { initPoolCoinMintAmount = GenInitPoolCoinMintAmount(r) }, + ) + + var maxReserveCoinAmount sdk.Int + simState.AppParams.GetOrGenerate( + simState.Cdc, MaxReserveCoinAmount, &maxReserveCoinAmount, simState.Rand, + func(r *rand.Rand) { maxReserveCoinAmount = GenMaxReserveCoinAmount(r) }, + ) + + var poolCreationFee sdk.Coins + simState.AppParams.GetOrGenerate( + simState.Cdc, PoolCreationFee, &poolCreationFee, simState.Rand, + func(r *rand.Rand) { poolCreationFee = GenPoolCreationFee(r) }, + ) + + var swapFeeRate sdk.Dec + simState.AppParams.GetOrGenerate( + simState.Cdc, SwapFeeRate, &swapFeeRate, simState.Rand, + func(r *rand.Rand) { swapFeeRate = GenSwapFeeRate(r) }, + ) + + var withdrawFeeRate sdk.Dec + simState.AppParams.GetOrGenerate( + simState.Cdc, WithdrawFeeRate, &withdrawFeeRate, simState.Rand, + func(r *rand.Rand) { withdrawFeeRate = GenWithdrawFeeRate(r) }, + ) + + var maxOrderAmountRatio sdk.Dec + simState.AppParams.GetOrGenerate( + simState.Cdc, MaxOrderAmountRatio, &maxOrderAmountRatio, simState.Rand, + func(r *rand.Rand) { maxOrderAmountRatio = GenMaxOrderAmountRatio(r) }, + ) + + var unitBatchHeight uint32 + simState.AppParams.GetOrGenerate( + simState.Cdc, UnitBatchHeight, &unitBatchHeight, simState.Rand, + func(r *rand.Rand) { unitBatchHeight = GenUnitBatchHeight(r) }, + ) + + liquidityGenesis := types.GenesisState{ + Params: types.Params{ + PoolTypes: liquidityPoolTypes, + MinInitDepositAmount: minInitDepositAmount, + InitPoolCoinMintAmount: initPoolCoinMintAmount, + MaxReserveCoinAmount: maxReserveCoinAmount, + PoolCreationFee: poolCreationFee, + SwapFeeRate: swapFeeRate, + WithdrawFeeRate: withdrawFeeRate, + MaxOrderAmountRatio: maxOrderAmountRatio, + UnitBatchHeight: unitBatchHeight, + }, + PoolRecords: []types.PoolRecord{}, + } + + bz, _ := json.MarshalIndent(&liquidityGenesis, "", " ") + fmt.Printf("Selected randomly generated liquidity parameters:\n%s\n", bz) + simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(&liquidityGenesis) +} diff --git a/x/liquidity/simulation/genesis_test.go b/x/liquidity/simulation/genesis_test.go new file mode 100644 index 00000000000..c42887f6bbe --- /dev/null +++ b/x/liquidity/simulation/genesis_test.go @@ -0,0 +1,84 @@ +package simulation_test + +import ( + "encoding/json" + "math/rand" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/x/liquidity/simulation" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// TestRandomizedGenState tests the normal scenario of applying RandomizedGenState. +// Abnormal scenarios are not tested here. +func TestRandomizedGenState(t *testing.T) { + interfaceRegistry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + s := rand.NewSource(1) + r := rand.New(s) + + simState := module.SimulationState{ + AppParams: make(simtypes.AppParams), + Cdc: cdc, + Rand: r, + NumBonded: 3, + Accounts: simtypes.RandomAccounts(r, 3), + InitialStake: 1000, + GenState: make(map[string]json.RawMessage), + } + + simulation.RandomizedGenState(&simState) + + var liquidityGenesis types.GenesisState + simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &liquidityGenesis) + + dec1, _ := sdk.NewIntFromString("4122540") + dec2, _ := sdk.NewIntFromString("11240456") + dec3, _ := sdk.NewIntFromString("2040480279449") + dec4, _ := sdk.NewDecFromStr("0.448590000000000000") + dec5, _ := sdk.NewDecFromStr("0.732160000000000000") + dec6, _ := sdk.NewDecFromStr("0.237840000000000000") + + require.Equal(t, dec1, liquidityGenesis.Params.MinInitDepositAmount) + require.Equal(t, dec2, liquidityGenesis.Params.InitPoolCoinMintAmount) + require.Equal(t, dec3, liquidityGenesis.Params.MaxReserveCoinAmount) + require.Equal(t, dec4, liquidityGenesis.Params.SwapFeeRate) + require.Equal(t, dec5, liquidityGenesis.Params.WithdrawFeeRate) + require.Equal(t, dec6, liquidityGenesis.Params.MaxOrderAmountRatio) + require.Equal(t, uint32(6), liquidityGenesis.Params.UnitBatchHeight) +} + +// TestRandomizedGenState tests abnormal scenarios of applying RandomizedGenState. +func TestRandomizedGenState1(t *testing.T) { + interfaceRegistry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + s := rand.NewSource(1) + r := rand.New(s) + + // all these tests will panic + tests := []struct { + simState module.SimulationState + panicMsg string + }{ + { // panic => reason: incomplete initialization of the simState + module.SimulationState{}, "invalid memory address or nil pointer dereference"}, + { // panic => reason: incomplete initialization of the simState + module.SimulationState{ + AppParams: make(simtypes.AppParams), + Cdc: cdc, + Rand: r, + }, "assignment to entry in nil map"}, + } + + for _, tt := range tests { + require.Panicsf(t, func() { simulation.RandomizedGenState(&tt.simState) }, tt.panicMsg) + } +} diff --git a/x/liquidity/simulation/operations.go b/x/liquidity/simulation/operations.go new file mode 100644 index 00000000000..4fc08415186 --- /dev/null +++ b/x/liquidity/simulation/operations.go @@ -0,0 +1,387 @@ +package simulation + +import ( + "math/rand" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp/helpers" + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + + liquidityparams "github.com/cosmos/gaia/v9/app/params" + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// Simulation operation weights constants. +// +//nolint:gosec +const ( + OpWeightMsgCreatePool = "op_weight_msg_create_pool" + OpWeightMsgDepositWithinBatch = "op_weight_msg_deposit_to_pool" + OpWeightMsgWithdrawWithinBatch = "op_weight_msg_withdraw_from_pool" + OpWeightMsgSwapWithinBatch = "op_weight_msg_swap" +) + +// WeightedOperations returns all the operations from the module with their respective weights. +func WeightedOperations( + appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, + bk types.BankKeeper, k keeper.Keeper, +) simulation.WeightedOperations { + var weightMsgCreatePool int + appParams.GetOrGenerate(cdc, OpWeightMsgCreatePool, &weightMsgCreatePool, nil, + func(_ *rand.Rand) { + weightMsgCreatePool = liquidityparams.DefaultWeightMsgCreatePool + }, + ) + + var weightMsgDepositWithinBatch int + appParams.GetOrGenerate(cdc, OpWeightMsgDepositWithinBatch, &weightMsgDepositWithinBatch, nil, + func(_ *rand.Rand) { + weightMsgDepositWithinBatch = liquidityparams.DefaultWeightMsgDepositWithinBatch + }, + ) + + var weightMsgMsgWithdrawWithinBatch int + appParams.GetOrGenerate(cdc, OpWeightMsgWithdrawWithinBatch, &weightMsgMsgWithdrawWithinBatch, nil, + func(_ *rand.Rand) { + weightMsgMsgWithdrawWithinBatch = liquidityparams.DefaultWeightMsgWithdrawWithinBatch + }, + ) + + var weightMsgSwapWithinBatch int + appParams.GetOrGenerate(cdc, OpWeightMsgSwapWithinBatch, &weightMsgSwapWithinBatch, nil, + func(_ *rand.Rand) { + weightMsgSwapWithinBatch = liquidityparams.DefaultWeightMsgSwapWithinBatch + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgCreatePool, + SimulateMsgCreatePool(ak, bk, k), + ), + simulation.NewWeightedOperation( + weightMsgDepositWithinBatch, + SimulateMsgDepositWithinBatch(ak, bk, k), + ), + simulation.NewWeightedOperation( + weightMsgMsgWithdrawWithinBatch, + SimulateMsgWithdrawWithinBatch(ak, bk, k), + ), + simulation.NewWeightedOperation( + weightMsgSwapWithinBatch, + SimulateMsgSwapWithinBatch(ak, bk, k), + ), + } +} + +// SimulateMsgCreatePool generates a MsgCreatePool with random values +func SimulateMsgCreatePool(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + var simAccount simtypes.Account + randomAccounts = simtypes.RandomAccounts(r, 3) + simAccount = randomAccounts[r.Intn(3)] + + params := k.GetParams(ctx) + params.MaxReserveCoinAmount = GenMaxReserveCoinAmount(r) + k.SetParams(ctx, params) + + // get randomized two denoms to create liquidity pool + var mintingDenoms []string + denomA, denomB := randomDenoms(r) + reserveCoinDenoms := []string{denomA, denomB} + mintingDenoms = append(mintingDenoms, reserveCoinDenoms...) + + // simAccount should have some fees to pay for transaction and pool creation fee + var feeDenoms []string + for _, fee := range params.PoolCreationFee { + feeDenoms = append(feeDenoms, fee.GetDenom()) + } + mintingDenoms = append(mintingDenoms, feeDenoms...) + + // mint coins of randomized and fee denoms + err := mintCoins(ctx, r, bk, simAccount, mintingDenoms) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreatePool, "unable to mint and send coins"), nil, err + } + + account := ak.GetAccount(ctx, simAccount.Address) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + poolName := types.PoolName(reserveCoinDenoms, types.DefaultPoolTypeID) + reserveAcc := types.GetPoolReserveAcc(poolName, false) + + // ensure the liquidity pool doesn't exist + _, found := k.GetPoolByReserveAccIndex(ctx, reserveAcc) + if found { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreatePool, "liquidity pool already exists"), nil, nil + } + + balanceA := bk.GetBalance(ctx, simAccount.Address, denomA).Amount + if balanceA.IsNegative() { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreatePool, "balanceA is negative"), nil, nil + } + + balanceB := bk.GetBalance(ctx, simAccount.Address, denomB).Amount + if balanceB.IsNegative() { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreatePool, "balanceB is negative"), nil, nil + } + + poolCreator := account.GetAddress() + depositCoinA := randomDepositCoin(r, params.MinInitDepositAmount, denomA) + depositCoinB := randomDepositCoin(r, params.MinInitDepositAmount, denomB) + depositCoins := sdk.NewCoins(depositCoinA, depositCoinB) + + // it will fail if the total reserve coin amount after the deposit is larger than the parameter + err = types.ValidateReserveCoinLimit(params.MaxReserveCoinAmount, depositCoins) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreatePool, "can not exceed reserve coin limit amount"), nil, nil + } + + msg := types.NewMsgCreatePool(poolCreator, types.DefaultPoolTypeID, depositCoins) + + fees, err := randomFees(r, spendable) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreatePool, "unable to generate fees"), nil, err + } + + txGen := liquidityparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + simAccount.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil + } +} + +// SimulateMsgDepositWithinBatch generates a MsgDepositWithinBatch with random values +func SimulateMsgDepositWithinBatch(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + if len(k.GetAllPools(ctx)) == 0 { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgDepositWithinBatch, "number of liquidity pools equals zero"), nil, nil + } + + pool, ok := randomLiquidity(r, k, ctx) + if !ok { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgDepositWithinBatch, "unable to pick liquidity pool"), nil, nil + } + + reserveCoinDenomA := pool.ReserveCoinDenoms[0] + reserveCoinDenomB := pool.ReserveCoinDenoms[1] + + // select random simulated account and mint reserve coins + // note that select the simulated account that has some balances of reserve coin denoms result in + // many failed transactions due to random accounts change after a creating pool. + simAccount := randomAccounts[r.Intn(len(randomAccounts))] + err := mintCoins(ctx, r, bk, simAccount, []string{reserveCoinDenomA, reserveCoinDenomB}) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgDepositWithinBatch, "unable to mint and send coins"), nil, err + } + + params := k.GetParams(ctx) + params.MaxReserveCoinAmount = GenMaxReserveCoinAmount(r) + k.SetParams(ctx, params) + + account := ak.GetAccount(ctx, simAccount.Address) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + depositor := account.GetAddress() + depositCoinA := randomDepositCoin(r, params.MinInitDepositAmount, reserveCoinDenomA) + depositCoinB := randomDepositCoin(r, params.MinInitDepositAmount, reserveCoinDenomB) + depositCoins := sdk.NewCoins(depositCoinA, depositCoinB) + + reserveCoins := k.GetReserveCoins(ctx, pool) + + // it will fail if the total reserve coin amount after the deposit is larger than the parameter + err = types.ValidateReserveCoinLimit(params.MaxReserveCoinAmount, reserveCoins.Add(depositCoinA, depositCoinB)) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgDepositWithinBatch, "can not exceed reserve coin limit amount"), nil, nil + } + + fees, err := randomFees(r, spendable) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgDepositWithinBatch, "unable to generate fees"), nil, err + } + + msg := types.NewMsgDepositWithinBatch(depositor, pool.Id, depositCoins) + + txGen := liquidityparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + simAccount.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil + } +} + +// SimulateMsgWithdrawWithinBatch generates a MsgWithdrawWithinBatch with random values. +func SimulateMsgWithdrawWithinBatch(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + if len(k.GetAllPools(ctx)) == 0 { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawWithinBatch, "number of liquidity pools equals zero"), nil, nil + } + + pool, ok := randomLiquidity(r, k, ctx) + if !ok { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawWithinBatch, "unable to pick liquidity pool"), nil, nil + } + + poolCoinDenom := pool.GetPoolCoinDenom() + + // select random simulated account and mint reserve coins + // note that select the simulated account that has some balance of pool coin denom result in + // many failed transactions due to random accounts change after a creating pool. + simAccount := randomAccounts[r.Intn(len(randomAccounts))] + err := mintCoins(ctx, r, bk, simAccount, []string{poolCoinDenom}) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawWithinBatch, "unable to mint and send coins"), nil, err + } + + // if simAccount.PrivKey == nil, then no account has pool coin denom balanace + if simAccount.PrivKey == nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawWithinBatch, "account private key is nil"), nil, nil + } + + account := ak.GetAccount(ctx, simAccount.Address) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + balance := bk.GetBalance(ctx, simAccount.Address, poolCoinDenom) + withdrawer := account.GetAddress() + withdrawCoin := randomWithdrawCoin(r, poolCoinDenom, balance.Amount) + + msg := types.NewMsgWithdrawWithinBatch(withdrawer, pool.Id, withdrawCoin) + + fees, err := randomFees(r, spendable) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawWithinBatch, "unable to generate fees"), nil, err + } + + txGen := liquidityparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + simAccount.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil + } +} + +// SimulateMsgSwapWithinBatch generates a MsgSwapWithinBatch with random values +func SimulateMsgSwapWithinBatch(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + if len(k.GetAllPools(ctx)) == 0 { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSwapWithinBatch, "number of liquidity pools equals zero"), nil, nil + } + + pool, ok := randomLiquidity(r, k, ctx) + if !ok { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSwapWithinBatch, "unable to pick liquidity pool"), nil, nil + } + + reserveCoinDenomA := pool.ReserveCoinDenoms[0] + reserveCoinDenomB := pool.ReserveCoinDenoms[1] + + // select random simulated account and mint reserve coins + // note that select the simulated account that has some balances of reserve coin denoms result in + // many failed transactions due to random accounts change after a creating pool. + simAccount := randomAccounts[r.Intn(len(randomAccounts))] + err := mintCoins(ctx, r, bk, simAccount, []string{reserveCoinDenomA, reserveCoinDenomB}) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSwapWithinBatch, "unable to mint and send coins"), nil, err + } + + account := ak.GetAccount(ctx, simAccount.Address) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + swapRequester := account.GetAddress() + offerCoin := randomOfferCoin(r, k, ctx, pool, pool.ReserveCoinDenoms[0]) + demandCoinDenom := pool.ReserveCoinDenoms[1] + orderPrice := randomOrderPrice(r) + swapFeeRate := GenSwapFeeRate(r) + + // set randomly generated swap fee rate in params to prevent from miscalculation + params := k.GetParams(ctx) + params.SwapFeeRate = swapFeeRate + k.SetParams(ctx, params) + + msg := types.NewMsgSwapWithinBatch(swapRequester, pool.Id, types.DefaultSwapTypeID, offerCoin, demandCoinDenom, orderPrice, swapFeeRate) + + fees, err := randomFees(r, spendable) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSwapWithinBatch, "unable to generate fees"), nil, err + } + + txGen := liquidityparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txGen, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + simAccount.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil + } +} diff --git a/x/liquidity/simulation/operations_test.go b/x/liquidity/simulation/operations_test.go new file mode 100644 index 00000000000..69163b111fd --- /dev/null +++ b/x/liquidity/simulation/operations_test.go @@ -0,0 +1,249 @@ +package simulation_test + +import ( + "math/rand" + "strings" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + lapp "github.com/cosmos/gaia/v9/app" + liquidityparams "github.com/cosmos/gaia/v9/app/params" + "github.com/cosmos/gaia/v9/x/liquidity/simulation" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// TestWeightedOperations tests the weights of the operations. +func TestWeightedOperations(t *testing.T) { + app, ctx := createTestApp(false) + + ctx.WithChainID("test-chain") + + cdc := app.AppCodec() + appParams := make(simtypes.AppParams) + + weightedOps := simulation.WeightedOperations(appParams, cdc, app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper) + + s := rand.NewSource(1) + r := rand.New(s) + accs := simtypes.RandomAccounts(r, 3) + + expected := []struct { + weight int + opMsgRoute string + opMsgName string + }{ + {liquidityparams.DefaultWeightMsgCreatePool, types.ModuleName, types.TypeMsgCreatePool}, + {liquidityparams.DefaultWeightMsgDepositWithinBatch, types.ModuleName, types.TypeMsgDepositWithinBatch}, + {liquidityparams.DefaultWeightMsgWithdrawWithinBatch, types.ModuleName, types.TypeMsgWithdrawWithinBatch}, + {liquidityparams.DefaultWeightMsgSwapWithinBatch, types.ModuleName, types.TypeMsgSwapWithinBatch}, + } + + for i, w := range weightedOps { + operationMsg, _, _ := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID()) + // the following checks are very much dependent from the ordering of the output given + // by WeightedOperations. if the ordering in WeightedOperations changes some tests + // will fail + require.Equal(t, expected[i].weight, w.Weight(), "weight should be the same") + require.Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same") + require.Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same") + } +} + +// TestSimulateMsgCreatePool tests the normal scenario of a valid message of type TypeMsgCreatePool. +// Abnormal scenarios, where the message are created by an errors are not tested here. +func TestSimulateMsgCreatePool(t *testing.T) { + app, ctx := createTestApp(false) + + // setup a single account + s := rand.NewSource(1) + r := rand.New(s) + accounts := getTestingAccounts(t, r, app, ctx, 1) + + // setup randomly generated liquidity pool creation fees + feeCoins := simulation.GenPoolCreationFee(r) + params := app.LiquidityKeeper.GetParams(ctx) + params.PoolCreationFee = feeCoins + app.LiquidityKeeper.SetParams(ctx, params) + + // begin a new block + app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}}) + + // execute operation + op := simulation.SimulateMsgCreatePool(app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper) + operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "") + require.NoError(t, err) + + var msg types.MsgCreatePool + require.NoError(t, types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)) + + require.True(t, operationMsg.OK) + require.Equal(t, "cosmos10kn7aww37y27c4lggjx6mycyhr927677rkp7x0", msg.GetPoolCreator().String()) + require.Equal(t, types.DefaultPoolTypeID, msg.PoolTypeId) + require.Equal(t, "90341750hsuk,28960633ijmo", msg.DepositCoins.String()) + require.Equal(t, types.TypeMsgCreatePool, msg.Type()) + require.Len(t, futureOperations, 0) +} + +// TestSimulateMsgDepositWithinBatch tests the normal scenario of a valid message of type TypeMsgDepositWithinBatch. +// Abnormal scenarios, where the message are created by an errors are not tested here. +func TestSimulateMsgDepositWithinBatch(t *testing.T) { + app, ctx := createTestApp(false) + + // setup accounts + s := rand.NewSource(1) + r := rand.New(s) + accounts := getTestingAccounts(t, r, app, ctx, 1) + + // setup random liquidity pools + setupLiquidityPools(t, r, app, ctx, accounts) + + // begin a new block + app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}}) + + // execute operation + op := simulation.SimulateMsgDepositWithinBatch(app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper) + operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "") + require.NoError(t, err) + + var msg types.MsgDepositWithinBatch + require.NoError(t, types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)) + + require.True(t, operationMsg.OK) + require.Equal(t, "cosmos10kn7aww37y27c4lggjx6mycyhr927677rkp7x0", msg.GetDepositor().String()) + require.Equal(t, "38511541fgae,71186277jxulr", msg.DepositCoins.String()) + require.Equal(t, types.TypeMsgDepositWithinBatch, msg.Type()) + require.Len(t, futureOperations, 0) +} + +// TestSimulateMsgWithdrawWithinBatch tests the normal scenario of a valid message of type TypeMsgWithdrawWithinBatch. +// Abnormal scenarios, where the message are created by an errors are not tested here. +func TestSimulateMsgWithdrawWithinBatch(t *testing.T) { + app, ctx := createTestApp(false) + + // setup accounts + s := rand.NewSource(1) + r := rand.New(s) + accounts := getTestingAccounts(t, r, app, ctx, 1) + + // setup random liquidity pools + setupLiquidityPools(t, r, app, ctx, accounts) + + // begin a new block + app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}}) + + // execute operation + op := simulation.SimulateMsgWithdrawWithinBatch(app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper) + operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "") + require.NoError(t, err) + + var msg types.MsgWithdrawWithinBatch + require.NoError(t, types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)) + + require.True(t, operationMsg.OK) + require.Equal(t, "cosmos10kn7aww37y27c4lggjx6mycyhr927677rkp7x0", msg.GetWithdrawer().String()) + require.Equal(t, "3402627138556poolA295B958C22781F58E51E1E4E8205F5E8E041D65F7E7AB5D7DDECCFFA7A75B01", msg.PoolCoin.String()) + require.Equal(t, types.TypeMsgWithdrawWithinBatch, msg.Type()) + require.Len(t, futureOperations, 0) +} + +// TestSimulateMsgSwapWithinBatch tests the normal scenario of a valid message of type TypeMsgSwapWithinBatch. +// Abnormal scenarios, where the message are created by an errors are not tested here. +func TestSimulateMsgSwapWithinBatch(t *testing.T) { + app, ctx := createTestApp(false) + + // setup a single account + s := rand.NewSource(1) + r := rand.New(s) + accounts := getTestingAccounts(t, r, app, ctx, 1) + + // setup random liquidity pools + setupLiquidityPools(t, r, app, ctx, accounts) + + // begin a new block + app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}}) + + // execute operation + op := simulation.SimulateMsgSwapWithinBatch(app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper) + operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "") + require.NoError(t, err) + + var msg types.MsgSwapWithinBatch + require.NoError(t, types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)) + + require.True(t, operationMsg.OK) + require.Equal(t, "cosmos10kn7aww37y27c4lggjx6mycyhr927677rkp7x0", msg.GetSwapRequester().String()) + require.Equal(t, "6453297fgae", msg.OfferCoin.String()) + require.Equal(t, "jxulr", msg.DemandCoinDenom) + require.Equal(t, types.TypeMsgSwapWithinBatch, msg.Type()) + require.Len(t, futureOperations, 0) +} + +func createTestApp(isCheckTx bool) (*lapp.LiquidityApp, sdk.Context) { + app := lapp.Setup(false) + + ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{}) + app.MintKeeper.SetParams(ctx, minttypes.DefaultParams()) + app.MintKeeper.SetMinter(ctx, minttypes.DefaultInitialMinter()) + + return app, ctx +} + +func getTestingAccounts(t *testing.T, r *rand.Rand, app *lapp.LiquidityApp, ctx sdk.Context, n int) []simtypes.Account { + accounts := simtypes.RandomAccounts(r, n) + + initAmt := sdk.TokensFromConsensusPower(1_000_000, sdk.DefaultPowerReduction) + initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) + + // add coins to the accounts + for _, account := range accounts { + acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address) + app.AccountKeeper.SetAccount(ctx, acc) + lapp.SaveAccount(app, ctx, account.Address, initCoins) + } + + return accounts +} + +func setupLiquidityPools(t *testing.T, r *rand.Rand, app *lapp.LiquidityApp, ctx sdk.Context, accounts []simtypes.Account) { + params := app.StakingKeeper.GetParams(ctx) + + for _, account := range accounts { + // random denom with a length from 4 to 6 characters + denomA := simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 4, 6)) + denomB := simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 4, 6)) + denomA, denomB = types.AlphabeticalDenomPair(strings.ToLower(denomA), strings.ToLower(denomB)) + + fees := sdk.NewCoin(params.GetBondDenom(), sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e10, 1e12)))) + + // mint random amounts of denomA and denomB coins + mintCoinA := sdk.NewCoin(denomA, sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e14, 1e15)))) + mintCoinB := sdk.NewCoin(denomB, sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e14, 1e15)))) + mintCoins := sdk.NewCoins(mintCoinA, mintCoinB, fees) + err := app.BankKeeper.MintCoins(ctx, types.ModuleName, mintCoins) + require.NoError(t, err) + + // transfer random amounts to the simulated random account + coinA := sdk.NewCoin(denomA, sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e12, 1e14)))) + coinB := sdk.NewCoin(denomB, sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e12, 1e14)))) + coins := sdk.NewCoins(coinA, coinB, fees) + err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, account.Address, coins) + require.NoError(t, err) + + // create liquidity pool with random deposit amounts + account := app.AccountKeeper.GetAccount(ctx, account.Address) + depositCoinA := sdk.NewCoin(denomA, sdk.NewInt(int64(simtypes.RandIntBetween(r, int(types.DefaultMinInitDepositAmount.Int64()), 1e8)))) + depositCoinB := sdk.NewCoin(denomB, sdk.NewInt(int64(simtypes.RandIntBetween(r, int(types.DefaultMinInitDepositAmount.Int64()), 1e8)))) + depositCoins := sdk.NewCoins(depositCoinA, depositCoinB) + + createPoolMsg := types.NewMsgCreatePool(account.GetAddress(), types.DefaultPoolTypeID, depositCoins) + + _, err = app.LiquidityKeeper.CreatePool(ctx, createPoolMsg) + require.NoError(t, err) + } +} diff --git a/x/liquidity/simulation/operations_utils.go b/x/liquidity/simulation/operations_utils.go new file mode 100644 index 00000000000..f4baf27418f --- /dev/null +++ b/x/liquidity/simulation/operations_utils.go @@ -0,0 +1,117 @@ +package simulation + +// DONTCOVER + +import ( + "math/rand" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// create simulated accounts due to gas usage overflow issue. +// Read this issue: https://github.com/tendermint/liquidity/issues/349 +var randomAccounts []simtypes.Account + +// mintCoins mints and send coins to the simulated account. +func mintCoins(ctx sdk.Context, r *rand.Rand, bk types.BankKeeper, acc simtypes.Account, denoms []string) error { + var mintCoins, sendCoins sdk.Coins + for _, denom := range denoms { + mintAmt := sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e15, 1e16))) + sendAmt := sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e13, 1e14))) + mintCoins = mintCoins.Add(sdk.NewCoin(denom, mintAmt)) + sendCoins = sendCoins.Add(sdk.NewCoin(denom, sendAmt)) + } + + feeCoin := int64(simtypes.RandIntBetween(r, 1e13, 1e14)) + mintCoins = mintCoins.Add(sdk.NewInt64Coin(sdk.DefaultBondDenom, feeCoin)) + sendCoins = sendCoins.Add(sdk.NewInt64Coin(sdk.DefaultBondDenom, feeCoin)) + + err := bk.MintCoins(ctx, types.ModuleName, mintCoins) + if err != nil { + return err + } + + err = bk.SendCoinsFromModuleToAccount(ctx, types.ModuleName, acc.Address, sendCoins) + if err != nil { + return err + } + + return nil +} + +// randomLiquidity returns a random liquidity pool. +func randomLiquidity(r *rand.Rand, k keeper.Keeper, ctx sdk.Context) (pool types.Pool, ok bool) { + pools := k.GetAllPools(ctx) + if len(pools) == 0 { + return types.Pool{}, false + } + + i := r.Intn(len(pools)) + + return pools[i], true +} + +// randomDepositCoin returns deposit amount between more than minimum deposit amount and less than 1e9. +func randomDepositCoin(r *rand.Rand, minInitDepositAmount sdk.Int, denom string) sdk.Coin { + amount := int64(simtypes.RandIntBetween(r, int(minInitDepositAmount.Int64()+1), 1e8)) + return sdk.NewInt64Coin(denom, amount) +} + +// randomWithdrawCoin returns random withdraw amount. +func randomWithdrawCoin(r *rand.Rand, denom string, balance sdk.Int) sdk.Coin { + // prevent panic from RandIntBetween + if balance.Quo(sdk.NewInt(10)).Int64() <= 1 { + return sdk.NewInt64Coin(denom, 1) + } + + amount := int64(simtypes.RandIntBetween(r, 1, int(balance.Quo(sdk.NewInt(10)).Int64()))) + return sdk.NewInt64Coin(denom, amount) +} + +// randomOfferCoin returns random offer amount of coin. +func randomOfferCoin(r *rand.Rand, k keeper.Keeper, ctx sdk.Context, pool types.Pool, denom string) sdk.Coin { + params := k.GetParams(ctx) + reserveCoinAmt := k.GetReserveCoins(ctx, pool).AmountOf(denom) + maximumOrderableAmt := reserveCoinAmt.ToDec().Mul(params.MaxOrderAmountRatio).TruncateInt() + amt := int64(simtypes.RandIntBetween(r, 1, int(maximumOrderableAmt.Int64()))) + return sdk.NewInt64Coin(denom, amt) +} + +// randomOrderPrice returns random order price that is sufficient for matchable swap. +func randomOrderPrice(r *rand.Rand) sdk.Dec { + return sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 1, 1e2)), 2) +} + +// randomFees returns a random amount of bond denom fee and +// if the user doesn't have enough funds for paying fees, it returns empty coins. +func randomFees(r *rand.Rand, spendableCoins sdk.Coins) (sdk.Coins, error) { + if spendableCoins.Empty() { + return nil, nil + } + + if spendableCoins.AmountOf(sdk.DefaultBondDenom).Equal(sdk.ZeroInt()) { + return nil, nil + } + + amt, err := simtypes.RandPositiveInt(r, spendableCoins.AmountOf(sdk.DefaultBondDenom)) + if err != nil { + return nil, err + } + + fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amt)) + + return fees, nil +} + +// randomDenoms returns randomly generated two different denoms that has a length anywhere between 4 and 6. +func randomDenoms(r *rand.Rand) (string, string) { + denomA := simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 4, 6)) + denomB := simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 4, 6)) + denomA, denomB = types.AlphabeticalDenomPair(strings.ToLower(denomA), strings.ToLower(denomB)) + return denomA, denomB +} diff --git a/x/liquidity/simulation/params.go b/x/liquidity/simulation/params.go new file mode 100644 index 00000000000..bf99c81863d --- /dev/null +++ b/x/liquidity/simulation/params.go @@ -0,0 +1,55 @@ +package simulation + +// DONTCOVER + +import ( + "fmt" + "math/rand" + + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// ParamChanges defines the parameters that can be modified by param change proposals +// on the simulation +func ParamChanges(r *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{ + simulation.NewSimParamChange(types.ModuleName, string(types.KeyMinInitDepositAmount), + func(r *rand.Rand) string { + return fmt.Sprintf("\"%d\"", GenMinInitDepositAmount(r).Int64()) + }, + ), + simulation.NewSimParamChange(types.ModuleName, string(types.KeyInitPoolCoinMintAmount), + func(r *rand.Rand) string { + return fmt.Sprintf("\"%d\"", GenInitPoolCoinMintAmount(r).Int64()) + }, + ), + simulation.NewSimParamChange(types.ModuleName, string(types.KeyMaxReserveCoinAmount), + func(r *rand.Rand) string { + return fmt.Sprintf("\"%d\"", GenMaxReserveCoinAmount(r).Int64()) + }, + ), + simulation.NewSimParamChange(types.ModuleName, string(types.KeySwapFeeRate), + func(r *rand.Rand) string { + return fmt.Sprintf("\"%s\"", GenSwapFeeRate(r)) + }, + ), + simulation.NewSimParamChange(types.ModuleName, string(types.KeyWithdrawFeeRate), + func(r *rand.Rand) string { + return fmt.Sprintf("\"%s\"", GenWithdrawFeeRate(r)) + }, + ), + simulation.NewSimParamChange(types.ModuleName, string(types.KeyMaxOrderAmountRatio), + func(r *rand.Rand) string { + return fmt.Sprintf("\"%s\"", GenMaxOrderAmountRatio(r)) + }, + ), + simulation.NewSimParamChange(types.ModuleName, string(types.KeyUnitBatchHeight), + func(r *rand.Rand) string { + return fmt.Sprintf("%d", GenUnitBatchHeight(r)) + }, + ), + } +} diff --git a/x/liquidity/simulation/params_test.go b/x/liquidity/simulation/params_test.go new file mode 100644 index 00000000000..075d9dcc3a3 --- /dev/null +++ b/x/liquidity/simulation/params_test.go @@ -0,0 +1,41 @@ +package simulation_test + +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/x/liquidity/simulation" +) + +func TestParamChanges(t *testing.T) { + s := rand.NewSource(1) + r := rand.New(s) + + expected := []struct { + composedKey string + key string + simValue string + subspace string + }{ + {"liquidity/MinInitDepositAmount", "MinInitDepositAmount", "\"3498081\"", "liquidity"}, + {"liquidity/InitPoolCoinMintAmount", "InitPoolCoinMintAmount", "\"40727887\"", "liquidity"}, + {"liquidity/MaxReserveCoinAmount", "MaxReserveCoinAmount", "\"4611666145821\"", "liquidity"}, + {"liquidity/SwapFeeRate", "SwapFeeRate", "\"0.934590000000000000\"", "liquidity"}, + {"liquidity/WithdrawFeeRate", "WithdrawFeeRate", "\"0.112010000000000000\"", "liquidity"}, + {"liquidity/MaxOrderAmountRatio", "MaxOrderAmountRatio", "\"0.560680000000000000\"", "liquidity"}, + {"liquidity/UnitBatchHeight", "UnitBatchHeight", "19", "liquidity"}, + } + + paramChanges := simulation.ParamChanges(r) + + require.Len(t, paramChanges, 7) + + for i, p := range paramChanges { + require.Equal(t, expected[i].composedKey, p.ComposedKey()) + require.Equal(t, expected[i].key, p.Key()) + require.Equal(t, expected[i].simValue, p.SimValue()(r)) + require.Equal(t, expected[i].subspace, p.Subspace()) + } +} diff --git a/x/liquidity/spec/01_concepts.md b/x/liquidity/spec/01_concepts.md new file mode 100644 index 00000000000..0b4a3d7d9f7 --- /dev/null +++ b/x/liquidity/spec/01_concepts.md @@ -0,0 +1,67 @@ + + + # Concepts + +## Liquidity Module + +The liquidity module is a module that can be used on any Cosmos SDK-based application. The liquidity module implements a decentralized exchange (DEX) that serves liquidity providing and coin swap functions. Anyone can create a liquidity pool with a pair of coins, provide liquidity by depositing reserve coins into the liquidity pool, and trade coins using the liquidity pool. All of the logic is designed to always protect the pool investors. + +## Liquidity Pool + +A liquidity pool is a coin reserve that contains two different types of coins in a trading pair. The trading pair has to be unique. A liquidity provider can be anyone (permissionless) who provides liquidity by depositing reserve coins into the pool. The liquidity provider earns the accumulated swap fees with respect to their pool share. The pool share is represented as possession of pool coins. All matchable swap requests are expected to be executed and unmatched swap requests are removed. +## Equivalent Swap Price Model (ESPM) + +The liquidity module is a Cosmos SDK implementation of an AMM system with a novel economic model called the Equivalent Swap Price Model (ESPM). + +The key distinguishing feature of the ESPM model from the Constant Product Market Maker (CPMM) model is the implementation of a hybrid system that combines an orderbook model exchange with a simple liquidity pool model that governs the order book with a set of order rules and performs execution in batches. In the ESPM, the pool price is always equal to the last swap price which reduces opportunities for arbitrage. + +The ESPM model is intended to provide protection against price volatility, transaction ordering vulnerabilities, and losses due to arbitrage. AMMs such as Uniswap do not provide this level of protection. + +## Batch Execution + +The liquidity module uses a batch execution methodology. Deposits, withdrawals, and swap orders are accumulated in a liquidity pool for a pre-defined period that is one or more blocks in length. Orders are then added to the pool and executed at the end of the batch. The size of each batch is configured by using the `UnitBatchSize` governance parameter. + +## Price Discovery + +Swap prices in liquidity pools are determined by the current pool coin reserves and the requested swap amount. Arbitrageurs buy or sell coins in liquidity pools to gain instant profit that results in real-time price discovery of liquidity pools. + +## Escrow Process + +The liquidity module uses a module account that acts as an escrow account. The module account holds and releases the coin amount during batch execution. + +## Refund + +The liquidity module has refund functions when deposit, withdraw, or swap batch states are not successfully executed. +Read [the batch transaction logic](https://github.com/tendermint/liquidity/blob/e8ab2f4d75079157d008eba9f310b199573eed28/x/liquidity/keeper/batch.go#L83-L127) in the code for more context. +## Fees + +You set liquidity module fees for pool creation, withdrawal, and swap in genesis state. These fees can be updated by the governance proposal. +### PoolCreationFee + +The liquidity module pool creation fee set by the `PoolCreationFee` parameter is paid on pool creation. The purpose of this fee is to prevent users from creating useless pools and making limitless transactions. The funds from this fee go to the community fund. +### WithdrawalFeeRate + +The liquidity module has `WithdrawFeeRate` parameter that is paid upon withdrawal. The purpose of this fee is to prevent from making limitless withdrawals. + +### SwapFeeRate + +Swap fees are paid upon swap orders. They are accumulated in the pools and are shared among the liquidity providers. The liquidity module implements half-half-fee mechanism that minimizes the impact of fee payment process. Read [the issue about fees in half offer coins, half exchanged coins](https://github.com/tendermint/liquidity/issues/41) to have more context. +## Pool Identification + +The pools in the liquidity module are identified with: +### PoolName + +- Concatenate two different reserve coin denoms and pool type id and forward slash `/` separator. + - Example: `uatom/stake/1` +### PoolReserveAccount + +- `sdk.AccAddress(crypto.AddressHash([]byte(PoolName)))` + - Example: `cosmos16ddqestwukv0jzcyfn3fdfq9h2wrs83cr4rfm3` (`D35A0CC16EE598F90B044CE296A405BA9C381E38`) +### PoolCoinDenom + +- `fmt.Sprintf("%s%X", PoolCoinDenomPrefix, sha256.Sum256([]byte(PoolName)))` +- Use `PoolCoinDenomPrefix` for `pool` + - Example: `poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4` + + + diff --git a/x/liquidity/spec/02_state.md b/x/liquidity/spec/02_state.md new file mode 100644 index 00000000000..831d917f4b0 --- /dev/null +++ b/x/liquidity/spec/02_state.md @@ -0,0 +1,123 @@ + + + # State + +The liquidity module `x/liquidity` keeps track of the Pool and PoolBatch states. The state represents your app at a given moment. +## Pool + +Pool stores information about the liquidity pool. + +Pool type has the following structure. + +```go +type Pool struct { + Id uint64 // index of this liquidity pool + TypeId uint32 // pool type of this liquidity pool + ReserveCoinDenoms []string // list of reserve coin denoms for this liquidity pool + ReserveAccountAddress string // reserve account address for this liquidity pool to store reserve coins + PoolCoinDenom string // denom of pool coin for this liquidity pool +} +``` + +The parameters of the Pool state are: + +- Pool: `0x11 | Id -> ProtocolBuffer(Pool)` + +- PoolByReserveAccIndex: `0x12 | ReserveAccLen (1 byte) | ReserveAcc -> ProtocolBuffer(uint64)` + +- GlobalLiquidityPoolIdKey: `[]byte("globalLiquidityPoolId")` + +- ModuleName, RouterKey, StoreKey, QuerierRoute: `liquidity` + +- PoolCoinDenomPrefix: `pool` +## PoolBatch + +PoolBatch stores information about the liquidity pool batch states. + +PoolBatch type has the following structure. + +```go +type PoolBatch struct { + PoolId uint64 // id of target liquidity pool + Index uint64 // index of this batch + BeginHeight uint64 // block height when batch is created + DepositMsgIndex uint64 // last index of DepositMsgStates + WithdrawMsgIndex uint64 // last index of WithdrawMsgStates + SwapMsgIndex uint64 // last index of SwapMsgStates + Executed bool // true if executed, false if not executed +} +``` + +## Batch Messages + +Deposit, withdrawal, or swap orders are accumulated in a liquidity pool for a pre-defined period, which can be one or more blocks in length. Orders are then added to the pool and executed at the end of the batch. The following messages are executed in batch-style. + +### DepositMsgState + +`DepositMsgState` defines the state of deposit message as it is processed in the next batch or batches. + +When a user sends `MsgDepositWithinBatch` transaction to the network, it is accumulated in a batch. `DepositMsgState` contains the state information about the message; if the transaction is executed, successfully matched, and if it is to be deleted in the next block. + +```go +type DepositMsgState struct { + MsgHeight int64 // block height where this message is appended to the batch + MsgIndex uint64 // index of this deposit message in this liquidity pool + Executed bool // true if executed on this batch, false if not executed + Succeeded bool // true if executed successfully on this batch, false if failed + ToBeDelete bool // true if ready to be deleted on kvstore, false if not ready to be deleted + Msg MsgDepositWithinBatch +} +``` +### WithdrawMsgState + +`WithdrawMsgState` defines the state of the withdraw message as it is processed in the next batch or batches. + +When a user sends a `MsgWithdrawWithinBatch` transaction to the network, it is accumulated in a batch. `WithdrawMsgState` contains the state information about the message: + +- If the transaction is executed +- If the transaction is successfully matched +- If the transaction will be deleted in the next block + +```go +type WithdrawMsgState struct { + MsgHeight int64 // block height where this message is appended to the batch + MsgIndex uint64 // index of this withdraw message in this liquidity pool + Executed bool // true if executed on this batch, false if not executed + Succeeded bool // true if executed successfully on this batch, false if failed + ToBeDelete bool // true if ready to be deleted on kvstore, false if not ready to be deleted + Msg MsgWithdrawWithinBatch +} +``` +### SwapMsgState + +`SwapMsgState` defines the state of swap message as it is processed in the next batch or batches. + +When a user sends a `MsgSwapWithinBatch` transaction to the network, it is accumulated in a batch. `SwapMsgState` contains the state information about the message: + +- If the transaction is executed +- If the transaction is successfully matched +- If the transaction will be deleted in the next block + +```go +type SwapMsgState struct { + MsgHeight int64 // block height where this message is appended to the batch + MsgIndex uint64 // index of this swap message in this liquidity pool + Executed bool // true if executed on this batch, false if not executed + Succeeded bool // true if executed successfully on this batch, false if failed + ToBeDelete bool // true if ready to be deleted on kvstore, false if not ready to be deleted + OrderExpiryHeight int64 // swap orders are cancelled when current height is equal to or greater than ExpiryHeight + ExchangedOfferCoin sdk.Coin // offer coin exchanged so far + RemainingOfferCoin sdk.Coin // offer coin remaining to be exchanged + Msg MsgSwapWithinBatch +} +``` + +The parameters of the PoolBatch, DepositMsgState, WithdrawMsgState, and SwapMsgState states are: + +- PoolBatch: `0x22 | PoolId -> ProtocolBuffer(PoolBatch)` + +- PoolBatchDepositMsgStates: `0x31 | PoolId | MsgIndex -> ProtocolBuffer(DepositMsgState)` + +- PoolBatchWithdrawMsgStates: `0x32 | PoolId | MsgIndex -> ProtocolBuffer(WithdrawMsgState)` + +- PoolBatchSwapMsgStates: `0x33 | PoolId | MsgIndex -> ProtocolBuffer(SwapMsgState)` diff --git a/x/liquidity/spec/03_state_transitions.md b/x/liquidity/spec/03_state_transitions.md new file mode 100644 index 00000000000..6b7c7f08dbb --- /dev/null +++ b/x/liquidity/spec/03_state_transitions.md @@ -0,0 +1,250 @@ + + + # State Transitions + +These messages (Msg) in the liquidity module trigger state transitions. + +## Coin Escrow for Liquidity Module Messages + +Transaction confirmation causes state transition on the [Bank](https://docs.cosmos.network/master/modules/bank/) module. Some messages on the liquidity module require coin escrow before confirmation. + +The coin escrow processes for each message type are: + +### MsgDepositWithinBatch + +To deposit coins into an existing `Pool`, the depositor must escrow `DepositCoins` into `LiquidityModuleEscrowAccount`. + +### MsgWithdrawWithinBatch + +To withdraw coins from a `Pool`, the withdrawer must escrow `PoolCoin` into `LiquidityModuleEscrowAccount`. + +### MsgSwapWithinBatch + +To request a coin swap, the swap requestor must escrow `OfferCoin` into `LiquidityModuleEscrowAccount`. + +## LiquidityPoolBatch Execution + +Batch execution causes state transitions on the `Bank` module. The following categories describe state transition executed by each process in the `PoolBatch` execution. + +### Coin Swap + +After a successful coin swap, coins accumulated in `LiquidityModuleEscrowAccount` for coin swaps are sent to other swap requestors(self-swap) or to the `Pool`(pool-swap). Fees are also sent to the liquidity `Pool`. + +### LiquidityPool Deposit + +After a successful deposit transaction, escrowed coins are sent to the `ReserveAccount` of the targeted `Pool` and new pool coins are minted and sent to the depositor. + +### LiquidityPool Withdrawal + +After a successful withdraw transaction, escrowed pool coins are burned and a corresponding amount of reserve coins are sent to the withdrawer from the liquidity `Pool`. + +## Pseudo Algorithm for LiquidityPoolBatch Execution + +If you are curious, you can see a Python simulation script on the B-Harvest [GitHub repo](https://github.com/b-harvest/Liquidity-Module-For-the-Hub/blob/master/pseudo-batch-execution-logic/batch.py). + +## Swap Price Calculation + +Swap execution applies a universal swap ratio for all swap requests. + +Swap price calculations are used for these cases. + +**Find price direction** + +Variables: + +- `X`: Reserve of X coin +- `Y`: Reserve of Y coin before this batch execution +- `PoolPrice` = `X`/`Y` +- `XOverLastPrice`: amount of orders that swap X for Y with order price higher than the last `PoolPrice` +- `XAtLastPrice`: amount of orders that swap X for Y with order price equal to the last `PoolPrice` +- `YUnderLastPrice`: amount of orders that swap Y for X with order price lower than last `PoolPrice` +- `YAtLastPrice`: amount of orders that swap Y for X with order price equal to the last `PoolPrice` + +- **Increase**: swap price is increased from the last `PoolPrice` + + - `XOverLastPrice` > (`YUnderLastPrice`+`YAtLastPrice`)*`PoolPrice` + +- **Decrease**: swap price is decreased from the last `PoolPrice` + + - `YUnderLastPrice` > (`XOverLastPrice`+`XAtLastPrice`)/`PoolPrice` + +- **Stay**: swap price is not changed from the last `PoolPrice` when the increase and decrease inequalities do not hold + +### Stay case + +Variables: + +- `swapPrice` = last `PoolPrice` +- `EX`: All executable orders that swap X for Y with order price equal to or greater than last `PoolPrice` +- `EY`: All executable orders that swap Y for X with order price equal or lower than last `PoolPrice` + +- **ExactMatch**: If `EX` == `EY`*`swapPrice` + + - Amount of X coins matched from swap orders = `EX` + - Amount of Y coins matched from swap orders = `EY` + +- **FractionalMatch** + + - If `EX` > `EY`*`swapPrice`: Residual X order amount remains + + - Amount of X coins matched from swap orders = `EY`*`swapPrice` + - Amount of Y coins matched from swap orders = `EY` + + - If `EY` > `EX`/`swapPrice`: Residual Y order amount remains + + - Amount of X coins matched from swap orders = `EX` + - Amount of Y coins matched from swap orders = `EX`/`swapPrice` + +### Increase case + +Iteration: iterate `orderPrice(i)` of all swap orders from low to high. + +Variables: + +- `EX(i)`: Sum of all order amount of swap orders that swap X for Y with order price equal or higher than this `orderPrice(i)` +- `EY(i)`: Sum of all order amounts of swap orders that swap Y for X with order price equal or lower than this `orderPrice(i)` + +- ExactMatch: SwapPrice is found between two orderPrices + + - `swapPrice(i)` = (`X` + 2_`EX(i)`)/(`Y` + 2_`EY(i-1)`) + + - condition1) `orderPrice(i-1)` < `swapPrice(i)` < `orderPrice(i)` + + - `PoolY(i)` = (`swapPrice(i)`_`Y` - `X`) / (2_`swapPrice(i)`) + + - condition2) `PoolY(i)` >= 0 + + - If both above conditions are met, `swapPrice` is the swap price for this iteration + + - Amount of X coins matched = `EX(i)` + + - If one of these conditions doesn't hold, go to FractionalMatch + +- FractionalMatch: SwapPrice is found at an orderPrice + + - `swapPrice(i)` = `orderPrice(i)` + - `PoolY(i)` = (`swapPrice(i)`_`Y` - `X`) / (2_`swapPrice(i)`) + - Amount of X coins matched: + + - `EX(i)` ← min[ `EX(i)`, (`EY(i)`+`PoolY(i)`)*`swapPrice(i)` ] + +- Find optimized swapPrice: + + - Find `swapPrice(k)` that has the largest amount of X coins matched + + - this is our optimized swap price + - corresponding swap result variables + + - `swapPrice(k)`, `EX(k)`, `EY(k)`, `PoolY(k)` + +### Decrease case + +Iteration: iterate `orderPrice(i)` of all swap orders from high to low. + +Variables: + +- `EX(i)`: Sum of all order amount of swap orders that swap X for Y with order price equal or higher than this `orderPrice(i)` +- `EY(i)`: Sum of all order amount of swap orders that swap Y for X with order price equal or lower than this `orderPrice(i)` + +- ExactMatch: SwapPrice is found between two orderPrices + +- `swapPrice(i)` = (`X` + 2_`EX(i)`)/(`Y` + 2_`EY(i-1)`) + + - condition1) `orderPrice(i)` < `swapPrice(i)` < `orderPrice(i-1)` + +- `PoolX(i)` = (`X` - `swapPrice(i)`*`Y`)/2 + + - condition2) `PoolX(i)` >= 0 + +- If both above conditions are met, `swapPrice` is the swap price for this iteration + + - Amount of Y coins matched = `EY(i)` + +- If one of these conditions doesn't hold, go to FractionalMatch + +- FractionalMatch: SwapPrice is found at an orderPrice + +- `swapPrice(i)` = `orderPrice(i)` + +- `PoolX(i)` = (`X` - `swapPrice(i)`*`Y`)/2 + +- Amount of Y coins matched: + + - `EY(i)` ← min[ `EY(i)`, (`EX(i)`+`PoolX(i)`)/`swapPrice(i)` ] + +- Find optimized swapPrice + + - Find `swapPrice(k)` that has the largest amount of Y coins matched + + - this is our optimized swap price + - corresponding swap result variables + + - `swapPrice(k)`, `EX(k)`, `EY(k)`, `PoolX(k)` + +### Calculate matching result + +- for swap orders from X to Y + + - Iteration: iterate `orderPrice(i)` of swap orders from X to Y (high to low) + + - sort by order price (high to low), sum all order amount with each `orderPrice(i)` + - if `EX(i)` ≤ `EX(k)` + + - `fractionalRatio` = 1 + + - if `EX(i)` > `EX(k)` + + - `fractionalRatio(i)` = (`EX(k)` - `EX(i-1)`) / (`EX(i)` - `EX(i-1)`) + - break the iteration + + - matching amount for swap orders with this `orderPrice(i)`: + + - `matchingAmt` = `offerAmt` * `fractionalRatio(i)` + +- for swap orders from Y to X + + - Iteration: iterate `orderPrice(i)` of swap orders from Y to X (low to high) + + - sort by order price (low to high), sum all order amount with each `orderPrice(i)` + - if `EY(i)` ≤ `EY(k)` + + - `fractionalRatio` = 1 + + - if `EY(i)` > `EY(k)` + + - `fractionalRatio(i)` = (`EY(k)` - `EY(i-1)`) / (`EY(i)` - `EY(i-1)`) + - break the iteration + + - matching amount for swap orders with this `orderPrice(i)`: + + - `matchingAmt` = `offerAmt` * `fractionalRatio(i)` + +### Swap Fee Payment + +Rather than taking fee solely from `OfferCoin`, liquidity module is designed to take fees half from `OfferCoin`, and the other half from `ExchangedCoin`. This smooths out an impact of the fee payment process. +- **OfferCoin Fee Reservation ( fee before batch process, in OfferCoin )** + - when user orders 100 Xcoin, the swap message demands + - `OfferCoin`(in Xcoin) : 100 + - `ReservedOfferCoinFeeAmount`(in Xcoin) = `OfferCoin`*(`SwapFeeRate`/2) + - user needs to have at least 100+100*(`SwapFeeRate`/2) amount of Xcoin to successfully commit this swap message + - the message fails when user's balance is below this amount +- **Actual Fee Payment** + - if 10 Xcoin is executed + - **OfferCoin Fee Payment from Reserved OfferCoin Fee** + - `OfferCoinFeeAmount`(in Xcoin) = (10/100)*`ReservedOfferCoinFeeAmount` + - `ReservedOfferCoinFeeAmount` is reduced from this fee payment + - **ExchangedCoin Fee Payment ( fee after batch process, in ExchangedCoin )** + - `ExchangedCoinFeeAmount`(in Ycoin) = `OfferCoinFeeAmount` / `SwapPrice` + - this is exactly equal value compared to advance fee payment assuming the current SwapPrice, to minimize the pool price impact from fee payment process + +- Swap fees are proportional to the coins received from matched swap orders. +- Swap fees are sent to the liquidity pool. +- The decimal points of the swap fees are rounded up. + +## Cancel unexecuted swap orders with expired CancelHeight + +After execution of `PoolBatch`, all remaining swap orders with `CancelHeight` equal to or higher than current height are cancelled. + +## Refund escrowed coins + +Refunds are issued for escrowed coins for cancelled swap order and failed create pool, deposit, and withdraw messages. diff --git a/x/liquidity/spec/04_messages.md b/x/liquidity/spec/04_messages.md new file mode 100644 index 00000000000..1cf2a383b6f --- /dev/null +++ b/x/liquidity/spec/04_messages.md @@ -0,0 +1,104 @@ + + + # Messages + +Messages (Msg) are objects that trigger state transitions. Msgs are wrapped in transactions (Txs) that clients submit to the network. The Cosmos SDK wraps and unwraps liquidity module messages from transactions. + +## MsgCreatePool + +A liquidity pool is created and initial coins are deposited with the `MsgCreatePool` message. + +```go +type MsgCreatePool struct { + PoolCreatorAddress string // account address of the origin of this message + PoolTypeId uint32 // id of the new liquidity pool + DepositCoins sdk.Coins // deposit initial coins for new liquidity pool +} +``` + +### Validity Checks + +Validity checks are performed for MsgCreatePool messages. The transaction that is triggered with `MsgCreatePool` fails if: + +- if `params.CircuitBreakerEnabled` is true +- `PoolCreator` address does not exist +- `PoolTypeId` does not exist in parameters +- A duplicate `LiquidityPool` with same `PoolTypeId` and `ReserveCoinDenoms` exists +- One or more coins in `ReserveCoinDenoms` do not exist in `bank` module +- The balance of `PoolCreator` does not have enough amount of coins for `DepositCoins` +- The balance of `PoolCreator` does not have enough coins for `PoolCreationFee` + +## MsgDepositWithinBatch + +Coins are deposited in a batch to a liquidity pool with the `MsgDepositWithinBatch` message. + +```go +type MsgDepositWithinBatch struct { + DepositorAddress string // account address of depositor that originated this message + PoolId uint64 // id of the liquidity pool to receive deposit + DepositCoins sdk.Coins // deposit coins +} +``` + +## Validity Checks + +The MsgDepositWithinBatch message performs validity checks. The transaction that is triggered with the `MsgDepositWithinBatch` message fails if: + +- if `params.CircuitBreakerEnabled` is true +- `Depositor` address does not exist +- `PoolId` does not exist +- The denoms of `DepositCoins` are not composed of existing `ReserveCoinDenoms` of the specified `LiquidityPool` +- The balance of `Depositor` does not have enough coins for `DepositCoins` + +## MsgWithdrawWithinBatch + +Withdraw coins in batch from liquidity pool with the `MsgWithdrawWithinBatch` message. + +```go +type MsgWithdrawWithinBatch struct { + WithdrawerAddress string // account address of the origin of this message + PoolId uint64 // id of the liquidity pool to withdraw the coins from + PoolCoin sdk.Coin // pool coin sent for reserve coin withdrawal +} +``` + +## Validity Checks + +The MsgWithdrawWithinBatch message performs validity checks. The transaction that is triggered with the `MsgWithdrawWithinBatch` message fails if: + +- `Withdrawer` address does not exist +- `PoolId` does not exist +- The denom of `PoolCoin` are not equal to the `PoolCoinDenom` of the `LiquidityPool` +- The balance of `Depositor` does not have enough coins for `PoolCoin` + +## MsgSwapWithinBatch + +Swap coins between liquidity pools in batch with the `MsgSwapWithinBatch` message. + +Offer coins are swapped with demand coins for the given order price. + +```go +type MsgSwapWithinBatch struct { + SwapRequesterAddress string // account address of the origin of this message + PoolId uint64 // id of the liquidity pool + SwapTypeId uint32 // swap type id of this swap message, default 1: InstantSwap, requesting instant swap + OfferCoin sdk.Coin // offer coin of this swap + DemandCoinDenom string // denom of demand coin of this swap + OfferCoinFee sdk.Coin // offer coin fee for pay fees in half offer coin + OrderPrice sdk.Dec // limit order price where the price is the exchange ratio of X/Y where X is the amount of the first coin and Y is the amount of the second coin when their denoms are sorted alphabetically +} +``` + +## Validity checks + +The MsgSwapWithinBatch message performs validity checks. The transaction that is triggered with the `MsgSwapWithinBatch` message fails if: + +- if `params.CircuitBreakerEnabled` is true +- `SwapRequester` address does not exist +- `PoolId` does not exist +- `SwapTypeId` does not exist +- Denoms of `OfferCoin` or `DemandCoin` do not exist in `bank` module +- The balance of `SwapRequester` does not have enough coins for `OfferCoin` +- `OrderPrice` <= zero +- `OfferCoinFee` equals `OfferCoin` * `params.SwapFeeRate` * `0.5` with ceiling +- Has sufficient balance `OfferCoinFee` to reserve offer coin fee diff --git a/x/liquidity/spec/05_begin_block.md b/x/liquidity/spec/05_begin_block.md new file mode 100644 index 00000000000..bfe2d735bc8 --- /dev/null +++ b/x/liquidity/spec/05_begin_block.md @@ -0,0 +1,18 @@ + + + # Begin-Block + +Begin block operations for the liquidity module reinitialize batch messages that were not executed in the previous batch and delete batch messages that were executed or ready to be deleted. + +## Delete pool batch messages and reset states for pool batch messages + +- Delete `{*action}MsgState` messages that have `ToBeDeleted` state +- Reset states for the remaining `{*action}MsgState` messages to execute on `end-block` of the next batch index + +## Reinitialize executed pool batch to next liquidity pool batch + +Reinitialize the executed `PoolBatch` for the next batch. The reinitialization process includes the following actions: + +- Increase state `BatchIndex` of the batch +- Reset state `BeginHeight` as current block height +- Reset state `Executed` as `false` diff --git a/x/liquidity/spec/06_end_block.md b/x/liquidity/spec/06_end_block.md new file mode 100644 index 00000000000..e0d0d2b7100 --- /dev/null +++ b/x/liquidity/spec/06_end_block.md @@ -0,0 +1,32 @@ + + + # Before-End-Block + +These operations occur before the end-block operations for the liquidity module. + +## Append messages to LiquidityPoolBatch + +After successful message verification and coin `escrow` process, the incoming `MsgDepositWithinBatch`, `MsgWithdrawWithinBatch`, and `MsgSwapWithinBatch` messages are appended to the current `PoolBatch` of the corresponding `Pool`. + +# End-Block + +End-block operations for the Liquidity Module. + +## Execute LiquidityPoolBatch upon execution heights + +If there are `{*action}MsgState` messages that have not yet executed in the `PoolBatch` for each `Pool`, the `PoolBatch` is executed. This batch contains one or more `DepositLiquidityPool`, `WithdrawLiquidityPool`, and `SwapExecution` processes. + +### Transact and refund for each message + +A liquidity module escrow account holds coins temporarily and releases them when state changes. Refunds from the escrow account are made for cancellations, partial cancellations, expiration, and failed messages. + +### Set states for each message according to the results + +After transact and refund transactions occur for each message, update the state of each `{*action}MsgState` message according to the results. + +Even if the message is completed or expired: + +1. Set the `ToBeDeleted` state value as true instead of deleting the message directly from the `end-block` +2. Delete the messages that have `ToBeDeleted` state from the begin-block in the next block so that each message with result state in the block can be stored to kvstore. + +This process allows searching for the past messages that have this result state. Searching is supported when the kvstore is not pruning. diff --git a/x/liquidity/spec/07_events.md b/x/liquidity/spec/07_events.md new file mode 100644 index 00000000000..74e6b160943 --- /dev/null +++ b/x/liquidity/spec/07_events.md @@ -0,0 +1,118 @@ + + + # Events + +The liquidity module emits the following events. + +## Handlers + +### MsgCreatePool + +Type | Attribute Key | Attribute Value +----------- | --------------- | ------------------------ +create_pool | pool_id | {poolId} +create_pool | pool_type_id | {poolTypeId} +create_pool | pool_name | {AttributeValuePoolName} +create_pool | reserve_account | {reserveAccountAddress} +create_pool | deposit_coins | {depositCoins} +create_pool | pool_coin_denom | {poolCoinDenom} +message | module | liquidity +message | action | create_pool +message | sender | {senderAddress} + +### MsgDepositWithinBatch + +Type | Attribute Key | Attribute Value +-------------------- | ------------- | -------------------- +deposit_within_batch | pool_id | {poolId} +deposit_within_batch | batch_index | {batchIndex} +deposit_within_batch | msg_index | {depositMsgIndex} +deposit_within_batch | deposit_coins | {depositCoins} +message | module | liquidity +message | action | deposit_within_batch +message | sender | {senderAddress} + +### MsgWithdrawWithinBatch + +Type | Attribute Key | Attribute Value +--------------------- | ---------------- | --------------------- +withdraw_within_batch | pool_id | {poolId} +withdraw_within_batch | batch_index | {batchIndex} +withdraw_within_batch | msg_index | {withdrawMsgIndex} +withdraw_within_batch | pool_coin_denom | {poolCoinDenom} +withdraw_within_batch | pool_coin_amount | {poolCoinAmount} +message | module | liquidity +message | action | withdraw_within_batch +message | sender | {senderAddress} + +### MsgSwapWithinBatch + +Type | Attribute Key | Attribute Value +----------------- | ----------------- | ----------------- +swap_within_batch | pool_id | {poolId} +swap_within_batch | batch_index | {batchIndex} +swap_within_batch | msg_index | {swapMsgIndex} +swap_within_batch | swap_type_id | {swapTypeId} +swap_within_batch | offer_coin_denom | {offerCoinDenom} +swap_within_batch | offer_coin_amount | {offerCoinAmount} +swap_within_batch | demand_coin_denom | {demandCoinDenom} +swap_within_batch | order_price | {orderPrice} +message | module | liquidity +message | action | swap_within_batch +message | sender | {senderAddress} + +## EndBlocker + +### Batch Result for MsgDepositWithinBatch + +Type | Attribute Key | Attribute Value +--------------- | ---------------- | ------------------ +deposit_to_pool | pool_id | {poolId} +deposit_to_pool | batch_index | {batchIndex} +deposit_to_pool | msg_index | {depositMsgIndex} +deposit_to_pool | depositor | {depositorAddress} +deposit_to_pool | accepted_coins | {acceptedCoins} +deposit_to_pool | refunded_coins | {refundedCoins} +deposit_to_pool | pool_coin_denom | {poolCoinDenom} +deposit_to_pool | pool_coin_amount | {poolCoinAmount} +deposit_to_pool | success | {success} + +### Batch Result for MsgWithdrawWithinBatch + +| Type | Attribute Key | Attribute Value | +| ------------------ | ------------------ | ------------------- | +| withdraw_from_pool | pool_id | {poolId} | +| withdraw_from_pool | batch_index | {batchIndex} | +| withdraw_from_pool | msg_index | {withdrawMsgIndex} | +| withdraw_from_pool | withdrawer | {withdrawerAddress} | +| withdraw_from_pool | pool_coin_denom | {poolCoinDenom} | +| withdraw_from_pool | pool_coin_amount | {poolCoinAmount} | +| withdraw_from_pool | withdraw_coins | {withdrawCoins} | +| withdraw_from_pool | withdraw_fee_coins | {withdrawFeeCoins} | +| withdraw_from_pool | success | {success} | + +### Batch Result for MsgSwapWithinBatch + +Type | Attribute Key | Attribute Value +--------------- | ------------------------------ | ---------------------------- +swap_transacted | pool_id | {poolId} +swap_transacted | batch_index | {batchIndex} +swap_transacted | msg_index | {swapMsgIndex} +swap_transacted | swap_requester | {swapRequesterAddress} +swap_transacted | swap_type_id | {swapTypeId} +swap_transacted | offer_coin_denom | {offerCoinDenom} +swap_transacted | offer_coin_amount | {offerCoinAmount} +swap_transacted | exchanged_coin_denom | {exchangedCoinDenom} +swap_transacted | order_price | {orderPrice} +swap_transacted | swap_price | {swapPrice} +swap_transacted | transacted_coin_amount | {transactedCoinAmount} +swap_transacted | remaining_offer_coin_amount | {remainingOfferCoinAmount} +swap_transacted | exchanged_offer_coin_amount | {exchangedOfferCoinAmount} +swap_transacted | exchanged_demand_coin_amount | {exchangedDemandCoinAmount} +swap_transacted | offer_coin_fee_amount | {offerCoinFeeAmount} +swap_transacted | exchanged_coin_fee_amount | {exchangedCoinFeeAmount} +swap_transacted | reserved_offer_coin_fee_amount | {reservedOfferCoinFeeAmount} +swap_transacted | order_expiry_height | {orderExpiryHeight} +swap_transacted | success | {success} + + diff --git a/x/liquidity/spec/08_params.md b/x/liquidity/spec/08_params.md new file mode 100644 index 00000000000..b00b8ef2e91 --- /dev/null +++ b/x/liquidity/spec/08_params.md @@ -0,0 +1,92 @@ + + + # Parameters + +The liquidity module contains the following parameters: + +Key | Type | Example +---------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------- +PoolTypes | []PoolType | [{"id":1,"name":"StandardLiquidityPool","min_reserve_coin_num":2,"max_reserve_coin_num":2,"description":"Standard liquidity pool with pool price function X/Y, ESPM constraint, and two kinds of reserve coins"}] +MinInitDepositAmount | string (sdk.Int) | "1000000" +InitPoolCoinMintAmount | string (sdk.Int) | "1000000" +MaxReserveCoinAmount | string (sdk.Int) | "0" +PoolCreationFee | sdk.Coins | [{"denom":"stake","amount":"40000000"}] +SwapFeeRate | string (sdk.Dec) | "0.003000000000000000" +WithdrawFeeRate | string (sdk.Dec) | "0.000000000000000000" +MaxOrderAmountRatio | string (sdk.Dec) | "0.100000000000000000" +UnitBatchHeight | uint32 | 1 +CircuitBreakerEnabled | bool | false + +## PoolTypes + +List of available PoolType + +```go +type PoolType struct { + Id uint32 + Name string + MinReserveCoinNum uint32 + MaxReserveCoinNum uint32 + Description string +} +``` + +## MinInitDepositAmount + +Minimum number of coins to be deposited to the liquidity pool upon pool creation. + +## InitPoolCoinMintAmount + +Initial mint amount of pool coin on pool creation. + +## MaxReserveCoinAmount + +Limit the size of each liquidity pool. The deposit transaction fails if the total reserve coin amount after the deposit is larger than the reserve coin amount. + +The default value of zero means no limit. + +**Note:** Especially in the early phases of liquidity module adoption, set `MaxReserveCoinAmount` to a non-zero value to minimize risk on error or exploitation. + +## PoolCreationFee + +Fee paid for to create a LiquidityPool creation. This fee prevents spamming and is collected in in the community pool of the distribution module. + +## SwapFeeRate + +Swap fee rate for every executed swap. When a swap is requested, the swap fee is reserved: + +- Half reserved as `OfferCoinFee` +- Half reserved as `ExchangedCoinFee` + +The swap fee is collected when a batch is executed. + +## WithdrawFeeRate + +Reserve coin withdrawal with less proportion by `WithdrawFeeRate`. This fee prevents attack vectors from repeated deposit/withdraw transactions. + +## MaxOrderAmountRatio + +Maximum ratio of reserve coins that can be ordered at a swap order. + +## UnitBatchHeight + +The smallest unit batch size for every liquidity pool. + +## CircuitBreakerEnabled + +The intention of circuit breaker is to have a contingency plan for a running network which maintains network liveness. This parameter enables or disables `MsgCreatePool`, `MsgDepositWithinBatch` and `MsgSwapWithinBatch` message types in liquidity module. +# Constant Variables + +Key | Type | Constant Value +------------------- | ------ | -------------- +CancelOrderLifeSpan | int64 | 0 +MinReserveCoinNum | uint32 | 2 +MaxReserveCoinNum | uint32 | 2 + +## CancelOrderLifeSpan + +The life span of swap orders in block heights. + +## MinReserveCoinNum, MaxReserveCoinNum + +The mininum and maximum number of reserveCoins for `PoolType`. diff --git a/x/liquidity/spec/README.md b/x/liquidity/spec/README.md new file mode 100644 index 00000000000..9faf82fde78 --- /dev/null +++ b/x/liquidity/spec/README.md @@ -0,0 +1,27 @@ + + + # `liquidity` + +## Abstract + +This document specifies the liquidity module of the Cosmos SDK that serves AMM (Automated Market Makers) style decentralized liquidity providing and coin swap functions. + +The module enables you to create a liquidity pool with a pair of coins, deposit reserve coins into the pool to provide liquidity, request withdrawal from the pool, and trade coins using the liquidity pool. + +This module is available in the Cosmos Hub and can be used by other blockchains that are based on the Cosmos SDK. + +## Contents + +1. **[Concepts](01_concepts.md)** +2. **[State](02_state.md)** +3. **[State Transitions](03_state_transitions.md)** +4. **[Messages](04_messages.md)** +5. **[Begin-Block](05_begin_block.md)** +6. **[End-Block](06_end_block.md)** +7. **[Events](07_events.md)** +8. **[Parameters](08_params.md)** + +## References + +- [Liquidity module proposal and milestone](https://github.com/b-harvest/Liquidity-Module-For-the-Hub) +- [Cosmos SDK modules](https://github.com/cosmos/cosmos-sdk/tree/master/x) diff --git a/x/liquidity/types/codec.go b/x/liquidity/types/codec.go new file mode 100644 index 00000000000..b227b0f8b8c --- /dev/null +++ b/x/liquidity/types/codec.go @@ -0,0 +1,48 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +// RegisterLegacyAminoCodec registers concrete types on the codec. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgCreatePool{}, "liquidity/MsgCreatePool", nil) + cdc.RegisterConcrete(&MsgDepositWithinBatch{}, "liquidity/MsgDepositWithinBatch", nil) + cdc.RegisterConcrete(&MsgWithdrawWithinBatch{}, "liquidity/MsgWithdrawWithinBatch", nil) + cdc.RegisterConcrete(&MsgSwapWithinBatch{}, "liquidity/MsgSwapWithinBatch", nil) +} + +// RegisterInterfaces registers the x/liquidity interface types with the +// interface registry +func RegisterInterfaces(registry types.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgCreatePool{}, + &MsgDepositWithinBatch{}, + &MsgWithdrawWithinBatch{}, + &MsgSwapWithinBatch{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +// legacy amino codecs +var ( + amino = codec.NewLegacyAmino() + + // ModuleCdc references the global x/liquidity module codec. Note, the + // codec should ONLY be used in certain instances of tests and for JSON + // encoding as Amino is still used for that purpose. + // + // The actual codec used for serialization should be provided to x/liquidity + // and defined at the application level. + ModuleCdc = codec.NewAminoCodec(amino) +) + +func init() { + RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) + amino.Seal() +} diff --git a/x/liquidity/types/errors.go b/x/liquidity/types/errors.go new file mode 100644 index 00000000000..82f73dc4d68 --- /dev/null +++ b/x/liquidity/types/errors.go @@ -0,0 +1,50 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// liquidity module sentinel errors +var ( + ErrPoolNotExists = sdkerrors.Register(ModuleName, 1, "pool not exists") + ErrPoolTypeNotExists = sdkerrors.Register(ModuleName, 2, "pool type not exists") + ErrEqualDenom = sdkerrors.Register(ModuleName, 3, "reserve coin denomination are equal") + ErrInvalidDenom = sdkerrors.Register(ModuleName, 4, "invalid denom") + ErrNumOfReserveCoin = sdkerrors.Register(ModuleName, 5, "invalid number of reserve coin") + ErrNumOfPoolCoin = sdkerrors.Register(ModuleName, 6, "invalid number of pool coin") + ErrInsufficientPool = sdkerrors.Register(ModuleName, 7, "insufficient pool") + ErrInsufficientBalance = sdkerrors.Register(ModuleName, 8, "insufficient coin balance") + ErrLessThanMinInitDeposit = sdkerrors.Register(ModuleName, 9, "deposit coin less than MinInitDepositAmount") + ErrNotImplementedYet = sdkerrors.Register(ModuleName, 10, "not implemented yet") + ErrPoolAlreadyExists = sdkerrors.Register(ModuleName, 11, "the pool already exists") + ErrPoolBatchNotExists = sdkerrors.Register(ModuleName, 12, "pool batch not exists") + ErrOrderBookInvalidity = sdkerrors.Register(ModuleName, 13, "orderbook is not validity") + ErrBatchNotExecuted = sdkerrors.Register(ModuleName, 14, "the liquidity pool batch is not executed") + ErrInvalidPoolCreatorAddr = sdkerrors.Register(ModuleName, 15, "invalid pool creator address") + ErrInvalidDepositorAddr = sdkerrors.Register(ModuleName, 16, "invalid pool depositor address") + ErrInvalidWithdrawerAddr = sdkerrors.Register(ModuleName, 17, "invalid pool withdrawer address") + ErrInvalidSwapRequesterAddr = sdkerrors.Register(ModuleName, 18, "invalid pool swap requester address") + ErrBadPoolCoinAmount = sdkerrors.Register(ModuleName, 19, "invalid pool coin amount") + ErrBadDepositCoinsAmount = sdkerrors.Register(ModuleName, 20, "invalid deposit coins amount") + ErrBadOfferCoinAmount = sdkerrors.Register(ModuleName, 21, "invalid offer coin amount") + ErrBadOrderingReserveCoin = sdkerrors.Register(ModuleName, 22, "reserve coin denoms not ordered alphabetical") + ErrBadOrderPrice = sdkerrors.Register(ModuleName, 23, "invalid order price") + ErrNumOfReserveCoinDenoms = sdkerrors.Register(ModuleName, 24, "invalid reserve coin denoms") + ErrEmptyReserveAccountAddress = sdkerrors.Register(ModuleName, 25, "empty reserve account address") + ErrEmptyPoolCoinDenom = sdkerrors.Register(ModuleName, 26, "empty pool coin denom") + ErrBadOrderingReserveCoinDenoms = sdkerrors.Register(ModuleName, 27, "bad ordering reserve coin denoms") + ErrBadReserveAccountAddress = sdkerrors.Register(ModuleName, 28, "bad reserve account address") + ErrBadPoolCoinDenom = sdkerrors.Register(ModuleName, 29, "bad pool coin denom") + ErrInsufficientPoolCreationFee = sdkerrors.Register(ModuleName, 30, "insufficient balances for pool creation fee") + ErrExceededMaxOrderable = sdkerrors.Register(ModuleName, 31, "can not exceed max order ratio of reserve coins that can be ordered at a order") + ErrBadBatchMsgIndex = sdkerrors.Register(ModuleName, 32, "bad msg index of the batch") + ErrSwapTypeNotExists = sdkerrors.Register(ModuleName, 33, "swap type not exists") + ErrLessThanMinOfferAmount = sdkerrors.Register(ModuleName, 34, "offer amount should be over 100 micro") + ErrBadOfferCoinFee = sdkerrors.Register(ModuleName, 35, "bad offer coin fee") + ErrNotMatchedReserveCoin = sdkerrors.Register(ModuleName, 36, "does not match the reserve coin of the pool") + ErrBadPoolTypeID = sdkerrors.Register(ModuleName, 37, "invalid index of the pool type") + ErrExceededReserveCoinLimit = sdkerrors.Register(ModuleName, 38, "can not exceed reserve coin limit amount") + ErrDepletedPool = sdkerrors.Register(ModuleName, 39, "the pool is depleted of reserve coin, reinitializing is required by deposit") + ErrCircuitBreakerEnabled = sdkerrors.Register(ModuleName, 40, "circuit breaker is triggered") + ErrOverflowAmount = sdkerrors.Register(ModuleName, 41, "invalid amount that can cause overflow") +) diff --git a/x/liquidity/types/events.go b/x/liquidity/types/events.go new file mode 100644 index 00000000000..50475c0bc34 --- /dev/null +++ b/x/liquidity/types/events.go @@ -0,0 +1,53 @@ +package types + +// Event types for the liquidity module. +const ( + EventTypeCreatePool = TypeMsgCreatePool + EventTypeDepositWithinBatch = TypeMsgDepositWithinBatch + EventTypeWithdrawWithinBatch = TypeMsgWithdrawWithinBatch + EventTypeSwapWithinBatch = TypeMsgSwapWithinBatch + EventTypeDepositToPool = "deposit_to_pool" + EventTypeWithdrawFromPool = "withdraw_from_pool" + EventTypeSwapTransacted = "swap_transacted" + + AttributeValuePoolId = "pool_id" //nolint:revive + AttributeValuePoolTypeId = "pool_type_id" //nolint:revive + AttributeValuePoolName = "pool_name" + AttributeValueReserveAccount = "reserve_account" + AttributeValuePoolCoinDenom = "pool_coin_denom" + AttributeValuePoolCoinAmount = "pool_coin_amount" + AttributeValueBatchIndex = "batch_index" + AttributeValueMsgIndex = "msg_index" + + AttributeValueDepositCoins = "deposit_coins" + + AttributeValueOfferCoinDenom = "offer_coin_denom" + AttributeValueOfferCoinAmount = "offer_coin_amount" + AttributeValueOfferCoinFeeAmount = "offer_coin_fee_amount" + AttributeValueExchangedCoinFeeAmount = "exchanged_coin_fee_amount" + AttributeValueDemandCoinDenom = "demand_coin_denom" + AttributeValueOrderPrice = "order_price" + + AttributeValueDepositor = "depositor" + AttributeValueRefundedCoins = "refunded_coins" + AttributeValueAcceptedCoins = "accepted_coins" + AttributeValueSuccess = "success" + AttributeValueWithdrawer = "withdrawer" + AttributeValueWithdrawCoins = "withdraw_coins" + AttributeValueWithdrawFeeCoins = "withdraw_fee_coins" + AttributeValueSwapRequester = "swap_requester" + AttributeValueSwapTypeId = "swap_type_id" //nolint:revive + AttributeValueSwapPrice = "swap_price" + + AttributeValueTransactedCoinAmount = "transacted_coin_amount" + AttributeValueRemainingOfferCoinAmount = "remaining_offer_coin_amount" + AttributeValueExchangedOfferCoinAmount = "exchanged_offer_coin_amount" + AttributeValueExchangedDemandCoinAmount = "exchanged_demand_coin_amount" + AttributeValueReservedOfferCoinFeeAmount = "reserved_offer_coin_fee_amount" + AttributeValueOrderExpiryHeight = "order_expiry_height" + + AttributeValueCategory = ModuleName + + Success = "success" + Failure = "failure" +) diff --git a/x/liquidity/types/expected_keepers.go b/x/liquidity/types/expected_keepers.go new file mode 100644 index 00000000000..60478f98229 --- /dev/null +++ b/x/liquidity/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" +) + +// BankKeeper defines the expected bank send keeper +type BankKeeper interface { + InputOutputCoins(ctx sdk.Context, inputs []banktypes.Input, outputs []banktypes.Output) error + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + + GetSupply(ctx sdk.Context, denom string) sdk.Coin + 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 + BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error + MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error +} + +// AccountKeeper defines the expected account keeper +type AccountKeeper interface { + GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI + GetModuleAddress(name string) sdk.AccAddress +} + +// DistributionKeeper defines the expected distribution keeper +type DistributionKeeper interface { + FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error +} diff --git a/x/liquidity/types/genesis.go b/x/liquidity/types/genesis.go new file mode 100644 index 00000000000..1f11496f610 --- /dev/null +++ b/x/liquidity/types/genesis.go @@ -0,0 +1,44 @@ +package types + +// NewGenesisState returns new GenesisState. +func NewGenesisState(params Params, liquidityPoolRecords []PoolRecord) *GenesisState { + return &GenesisState{ + Params: params, + PoolRecords: liquidityPoolRecords, + } +} + +// DefaultGenesisState returns the default genesis state. +func DefaultGenesisState() *GenesisState { + return NewGenesisState(DefaultParams(), []PoolRecord{}) +} + +// ValidateGenesis validates GenesisState. +func ValidateGenesis(data GenesisState) error { + if err := data.Params.Validate(); err != nil { + return err + } + for _, record := range data.PoolRecords { + if err := record.Validate(); err != nil { + return err + } + } + return nil +} + +// Validate validates PoolRecord. +func (record PoolRecord) Validate() error { + if record.PoolBatch.DepositMsgIndex == 0 || + (len(record.DepositMsgStates) > 0 && record.PoolBatch.DepositMsgIndex != record.DepositMsgStates[len(record.DepositMsgStates)-1].MsgIndex+1) { + return ErrBadBatchMsgIndex + } + if record.PoolBatch.WithdrawMsgIndex == 0 || + (len(record.WithdrawMsgStates) != 0 && record.PoolBatch.WithdrawMsgIndex != record.WithdrawMsgStates[len(record.WithdrawMsgStates)-1].MsgIndex+1) { + return ErrBadBatchMsgIndex + } + if record.PoolBatch.SwapMsgIndex == 0 || + (len(record.SwapMsgStates) != 0 && record.PoolBatch.SwapMsgIndex != record.SwapMsgStates[len(record.SwapMsgStates)-1].MsgIndex+1) { + return ErrBadBatchMsgIndex + } + return nil +} diff --git a/x/liquidity/types/genesis.pb.go b/x/liquidity/types/genesis.pb.go new file mode 100644 index 00000000000..888a87b911c --- /dev/null +++ b/x/liquidity/types/genesis.pb.go @@ -0,0 +1,856 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tendermint/liquidity/v1beta1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// records the state of each pool after genesis export or import, used to check variables +type PoolRecord struct { + Pool Pool `protobuf:"bytes,1,opt,name=pool,proto3" json:"pool" yaml:"pool"` + PoolMetadata PoolMetadata `protobuf:"bytes,2,opt,name=pool_metadata,json=poolMetadata,proto3" json:"pool_metadata" yaml:"pool_metadata"` + PoolBatch PoolBatch `protobuf:"bytes,3,opt,name=pool_batch,json=poolBatch,proto3" json:"pool_batch" yaml:"pool_batch"` + DepositMsgStates []DepositMsgState `protobuf:"bytes,4,rep,name=deposit_msg_states,json=depositMsgStates,proto3" json:"deposit_msg_states" yaml:"deposit_msg_states"` + WithdrawMsgStates []WithdrawMsgState `protobuf:"bytes,5,rep,name=withdraw_msg_states,json=withdrawMsgStates,proto3" json:"withdraw_msg_states" yaml:"withdraw_msg_states"` + SwapMsgStates []SwapMsgState `protobuf:"bytes,6,rep,name=swap_msg_states,json=swapMsgStates,proto3" json:"swap_msg_states" yaml:"swap_msg_states"` +} + +func (m *PoolRecord) Reset() { *m = PoolRecord{} } +func (m *PoolRecord) String() string { return proto.CompactTextString(m) } +func (*PoolRecord) ProtoMessage() {} +func (*PoolRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_7dc104913a173687, []int{0} +} +func (m *PoolRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PoolRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PoolRecord.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 *PoolRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_PoolRecord.Merge(m, src) +} +func (m *PoolRecord) XXX_Size() int { + return m.Size() +} +func (m *PoolRecord) XXX_DiscardUnknown() { + xxx_messageInfo_PoolRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_PoolRecord proto.InternalMessageInfo + +func (m *PoolRecord) GetPool() Pool { + if m != nil { + return m.Pool + } + return Pool{} +} + +func (m *PoolRecord) GetPoolMetadata() PoolMetadata { + if m != nil { + return m.PoolMetadata + } + return PoolMetadata{} +} + +func (m *PoolRecord) GetPoolBatch() PoolBatch { + if m != nil { + return m.PoolBatch + } + return PoolBatch{} +} + +func (m *PoolRecord) GetDepositMsgStates() []DepositMsgState { + if m != nil { + return m.DepositMsgStates + } + return nil +} + +func (m *PoolRecord) GetWithdrawMsgStates() []WithdrawMsgState { + if m != nil { + return m.WithdrawMsgStates + } + return nil +} + +func (m *PoolRecord) GetSwapMsgStates() []SwapMsgState { + if m != nil { + return m.SwapMsgStates + } + return nil +} + +// GenesisState defines the liquidity module's genesis state. +type GenesisState struct { + // params defines all the parameters for the liquidity module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + PoolRecords []PoolRecord `protobuf:"bytes,2,rep,name=pool_records,json=poolRecords,proto3" json:"pool_records" yaml:"pools"` +} + +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_7dc104913a173687, []int{1} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func init() { + proto.RegisterType((*PoolRecord)(nil), "tendermint.liquidity.v1beta1.PoolRecord") + proto.RegisterType((*GenesisState)(nil), "tendermint.liquidity.v1beta1.GenesisState") +} + +func init() { + proto.RegisterFile("tendermint/liquidity/v1beta1/genesis.proto", fileDescriptor_7dc104913a173687) +} + +var fileDescriptor_7dc104913a173687 = []byte{ + // 508 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0xc7, 0xed, 0x36, 0x8d, 0xe0, 0x92, 0x0a, 0x7a, 0x8d, 0x90, 0x1b, 0x55, 0x4e, 0x39, 0x21, + 0x11, 0x55, 0xd4, 0x56, 0xdb, 0xad, 0xa3, 0x85, 0xc4, 0x80, 0x22, 0x21, 0x77, 0x40, 0x62, 0x89, + 0x2e, 0xf1, 0xc9, 0x39, 0x29, 0xce, 0x1d, 0x7e, 0xd7, 0x98, 0x2c, 0x0c, 0x4c, 0x8c, 0x7c, 0x84, + 0x0e, 0x7c, 0x0f, 0xd6, 0x8e, 0x1d, 0x99, 0x2a, 0x94, 0x2c, 0xcc, 0x7c, 0x02, 0xe4, 0xf3, 0xe1, + 0x98, 0x80, 0x92, 0x4e, 0x3e, 0x9d, 0xff, 0xff, 0xff, 0xef, 0x3d, 0xdd, 0x7b, 0xe8, 0x58, 0xb1, + 0x49, 0xc4, 0xd2, 0x84, 0x4f, 0x94, 0x3f, 0xe6, 0xef, 0xaf, 0x78, 0xc4, 0xd5, 0xcc, 0x9f, 0x9e, + 0x0e, 0x98, 0xa2, 0xa7, 0x7e, 0xcc, 0x26, 0x0c, 0x38, 0x78, 0x32, 0x15, 0x4a, 0xe0, 0xc3, 0xa5, + 0xd6, 0x2b, 0xb5, 0x9e, 0xd1, 0xb6, 0x5f, 0xac, 0x4d, 0x5a, 0xea, 0x75, 0x56, 0xbb, 0x15, 0x8b, + 0x58, 0xe8, 0xa3, 0x9f, 0x9f, 0x8a, 0x5b, 0xf2, 0x75, 0x07, 0xa1, 0x37, 0x42, 0x8c, 0x43, 0x36, + 0x14, 0x69, 0x84, 0x5f, 0xa3, 0x9a, 0x14, 0x62, 0xec, 0xd8, 0x47, 0x76, 0xb7, 0x71, 0x46, 0xbc, + 0x75, 0x7c, 0x2f, 0xf7, 0x05, 0xfb, 0x37, 0x77, 0x1d, 0xeb, 0xd7, 0x5d, 0xa7, 0x31, 0xa3, 0xc9, + 0xf8, 0x82, 0xe4, 0x6e, 0x12, 0xea, 0x10, 0x9c, 0xa0, 0xdd, 0xfc, 0xdb, 0x4f, 0x98, 0xa2, 0x11, + 0x55, 0xd4, 0xd9, 0xd2, 0xa9, 0xc7, 0x9b, 0x53, 0x7b, 0xc6, 0x11, 0x1c, 0x9a, 0xf4, 0xd6, 0x32, + 0xbd, 0x8c, 0x23, 0x61, 0x53, 0x56, 0xb4, 0x98, 0x22, 0xa4, 0xff, 0x0f, 0xa8, 0x1a, 0x8e, 0x9c, + 0x6d, 0xcd, 0x7a, 0x7e, 0x8f, 0x0e, 0x72, 0x79, 0x70, 0x60, 0x40, 0x7b, 0x15, 0x90, 0x0e, 0x22, + 0xe1, 0x43, 0xf9, 0x47, 0x85, 0x3f, 0x22, 0x1c, 0x31, 0x29, 0x80, 0xab, 0x7e, 0x02, 0x71, 0x1f, + 0x14, 0x55, 0x0c, 0x9c, 0xda, 0xd1, 0x76, 0xb7, 0x71, 0x76, 0xb2, 0x1e, 0xf5, 0xb2, 0xf0, 0xf5, + 0x20, 0xbe, 0xcc, 0x5d, 0xc1, 0x53, 0x03, 0x3c, 0x28, 0x80, 0xff, 0xc6, 0x92, 0xf0, 0x71, 0xf4, + 0xb7, 0x07, 0xf0, 0x27, 0x1b, 0xed, 0x67, 0x5c, 0x8d, 0xa2, 0x94, 0x66, 0xd5, 0x0a, 0x76, 0x74, + 0x05, 0xde, 0xfa, 0x0a, 0xde, 0x1a, 0x63, 0x59, 0x02, 0x31, 0x25, 0xb4, 0x8b, 0x12, 0xfe, 0x13, + 0x4c, 0xc2, 0xbd, 0x6c, 0xc5, 0x05, 0x38, 0x45, 0x8f, 0x20, 0xa3, 0xb2, 0xca, 0xaf, 0x6b, 0xfe, + 0x86, 0x87, 0xbd, 0xcc, 0xa8, 0x2c, 0xd9, 0xae, 0x61, 0x3f, 0x29, 0xd8, 0x2b, 0x81, 0x24, 0xdc, + 0x85, 0x8a, 0x1a, 0xc8, 0x37, 0x1b, 0x35, 0x5f, 0x15, 0xab, 0xa1, 0x6f, 0x70, 0x80, 0xea, 0x92, + 0xa6, 0x34, 0x01, 0x33, 0xaa, 0xcf, 0x36, 0x3c, 0xb4, 0xd6, 0x06, 0xb5, 0x9c, 0x1a, 0x1a, 0x27, + 0xa6, 0x48, 0x0f, 0x50, 0x3f, 0xd5, 0xb3, 0x0f, 0xce, 0x96, 0xee, 0xa2, 0xbb, 0x79, 0x64, 0x8a, + 0x65, 0x09, 0x5a, 0xa6, 0x87, 0xe6, 0x72, 0x66, 0x80, 0x84, 0x0d, 0x59, 0x2a, 0xe0, 0xe2, 0xc1, + 0xe7, 0xeb, 0x8e, 0xf5, 0xf3, 0xba, 0x63, 0x05, 0xbd, 0x9b, 0xb9, 0x6b, 0xdf, 0xce, 0x5d, 0xfb, + 0xc7, 0xdc, 0xb5, 0xbf, 0x2c, 0x5c, 0xeb, 0x76, 0xe1, 0x5a, 0xdf, 0x17, 0xae, 0xf5, 0xee, 0x3c, + 0xe6, 0x6a, 0x74, 0x35, 0xf0, 0x86, 0x22, 0xf1, 0xe3, 0x94, 0x4e, 0xb9, 0x9a, 0x9d, 0x44, 0x6c, + 0x0a, 0x95, 0x9d, 0xfe, 0x50, 0x39, 0xab, 0x99, 0x64, 0x30, 0xa8, 0xeb, 0xf5, 0x3d, 0xff, 0x1d, + 0x00, 0x00, 0xff, 0xff, 0x59, 0xae, 0xc9, 0xf1, 0x4e, 0x04, 0x00, 0x00, +} + +func (m *PoolRecord) 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 *PoolRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PoolRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.SwapMsgStates) > 0 { + for iNdEx := len(m.SwapMsgStates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SwapMsgStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.WithdrawMsgStates) > 0 { + for iNdEx := len(m.WithdrawMsgStates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.WithdrawMsgStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.DepositMsgStates) > 0 { + for iNdEx := len(m.DepositMsgStates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DepositMsgStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + { + size, err := m.PoolBatch.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.PoolMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Pool.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 *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.PoolRecords) > 0 { + for iNdEx := len(m.PoolRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PoolRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PoolRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Pool.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = m.PoolMetadata.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = m.PoolBatch.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.DepositMsgStates) > 0 { + for _, e := range m.DepositMsgStates { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.WithdrawMsgStates) > 0 { + for _, e := range m.WithdrawMsgStates { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.SwapMsgStates) > 0 { + for _, e := range m.SwapMsgStates { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.PoolRecords) > 0 { + for _, e := range m.PoolRecords { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PoolRecord) 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: PoolRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PoolRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pool", 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.Pool.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolMetadata", 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.PoolMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolBatch", 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.PoolBatch.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DepositMsgStates", 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.DepositMsgStates = append(m.DepositMsgStates, DepositMsgState{}) + if err := m.DepositMsgStates[len(m.DepositMsgStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WithdrawMsgStates", 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.WithdrawMsgStates = append(m.WithdrawMsgStates, WithdrawMsgState{}) + if err := m.WithdrawMsgStates[len(m.WithdrawMsgStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SwapMsgStates", 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.SwapMsgStates = append(m.SwapMsgStates, SwapMsgState{}) + if err := m.SwapMsgStates[len(m.SwapMsgStates)-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 *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 PoolRecords", 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.PoolRecords = append(m.PoolRecords, PoolRecord{}) + if err := m.PoolRecords[len(m.PoolRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/liquidity/types/genesis_test.go b/x/liquidity/types/genesis_test.go new file mode 100644 index 00000000000..9418839345a --- /dev/null +++ b/x/liquidity/types/genesis_test.go @@ -0,0 +1,152 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestValidateGenesis(t *testing.T) { + testCases := []struct { + name string + configure func(*types.GenesisState) + errString string + }{ + { + "InvalidParams", + func(genState *types.GenesisState) { + params := types.DefaultParams() + params.SwapFeeRate = sdk.NewDec(-1) + genState.Params = params + }, + "swap fee rate must not be negative: -1.000000000000000000", + }, + { + "InvalidPoolRecords", + func(genState *types.GenesisState) { + genState.PoolRecords = []types.PoolRecord{{}} + }, + "bad msg index of the batch", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + genState := types.DefaultGenesisState() + tc.configure(genState) + err := types.ValidateGenesis(*genState) + require.EqualError(t, err, tc.errString) + }) + } +} + +func TestPoolRecord_Validate(t *testing.T) { + testCases := []struct { + name string + poolRecord types.PoolRecord + shouldFail bool + }{ + { + "ValidPoolRecord", + types.PoolRecord{ + PoolBatch: types.PoolBatch{ + DepositMsgIndex: 1, + WithdrawMsgIndex: 1, + SwapMsgIndex: 1, + }, + DepositMsgStates: nil, + WithdrawMsgStates: nil, + SwapMsgStates: nil, + }, + false, + }, + { + "InvalidPoolBatchDepositMsgIndex", + types.PoolRecord{ + PoolBatch: types.PoolBatch{ + DepositMsgIndex: 0, + WithdrawMsgIndex: 1, + SwapMsgIndex: 1, + }, + }, + true, + }, + { + "InvalidPoolBatchWithdrawMsgIndex", + types.PoolRecord{ + PoolBatch: types.PoolBatch{ + DepositMsgIndex: 0, + WithdrawMsgIndex: 1, + SwapMsgIndex: 0, + }, + }, + true, + }, + { + "InvalidPoolBatchSwapMsgIndex", + types.PoolRecord{ + PoolBatch: types.PoolBatch{ + DepositMsgIndex: 1, + WithdrawMsgIndex: 1, + SwapMsgIndex: 0, + }, + }, + true, + }, + { + "MismatchingPoolBatchDepositMsgIndex", + types.PoolRecord{ + PoolBatch: types.PoolBatch{ + DepositMsgIndex: 10, + WithdrawMsgIndex: 1, + SwapMsgIndex: 1, + }, + DepositMsgStates: []types.DepositMsgState{{MsgIndex: 1}}, + WithdrawMsgStates: nil, + SwapMsgStates: nil, + }, + true, + }, + { + "MismatchingPoolBatchWithdrawMsgIndex", + types.PoolRecord{ + PoolBatch: types.PoolBatch{ + DepositMsgIndex: 1, + WithdrawMsgIndex: 10, + SwapMsgIndex: 1, + }, + DepositMsgStates: nil, + WithdrawMsgStates: []types.WithdrawMsgState{{MsgIndex: 1}}, + SwapMsgStates: nil, + }, + true, + }, + { + "MismatchingPoolBatchSwapMsgIndex", + types.PoolRecord{ + PoolBatch: types.PoolBatch{ + DepositMsgIndex: 1, + WithdrawMsgIndex: 1, + SwapMsgIndex: 10, + }, + DepositMsgStates: nil, + WithdrawMsgStates: nil, + SwapMsgStates: []types.SwapMsgState{{MsgIndex: 1}}, + }, + true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.poolRecord.Validate() + if tc.shouldFail { + require.ErrorIs(t, err, types.ErrBadBatchMsgIndex) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/liquidity/types/keys.go b/x/liquidity/types/keys.go new file mode 100644 index 00000000000..22798d75e86 --- /dev/null +++ b/x/liquidity/types/keys.go @@ -0,0 +1,109 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" +) + +const ( + // ModuleName is the name of the liquidity module + ModuleName = "liquidity" + + // RouterKey is the message router key for the liquidity module + RouterKey = ModuleName + + // StoreKey is the default store key for the liquidity module + StoreKey = ModuleName + + // QuerierRoute is the querier route for the liquidity module + QuerierRoute = ModuleName + + // PoolCoinDenomPrefix is the prefix used for liquidity pool coin representation + PoolCoinDenomPrefix = "pool" +) + +var ( + // param key for global Liquidity Pool IDs + GlobalLiquidityPoolIDKey = []byte("globalLiquidityPoolId") + + PoolKeyPrefix = []byte{0x11} + PoolByReserveAccIndexKeyPrefix = []byte{0x12} + + PoolBatchKeyPrefix = []byte{0x22} + + PoolBatchDepositMsgStateIndexKeyPrefix = []byte{0x31} + PoolBatchWithdrawMsgStateIndexKeyPrefix = []byte{0x32} + PoolBatchSwapMsgStateIndexKeyPrefix = []byte{0x33} +) + +// GetPoolKey returns kv indexing key of the pool +func GetPoolKey(poolID uint64) []byte { + key := make([]byte, 9) + key[0] = PoolKeyPrefix[0] + copy(key[1:], sdk.Uint64ToBigEndian(poolID)) + return key +} + +// GetPoolByReserveAccIndexKey returns kv indexing key of the pool indexed by reserve account +func GetPoolByReserveAccIndexKey(reserveAcc sdk.AccAddress) []byte { + return append(PoolByReserveAccIndexKeyPrefix, address.MustLengthPrefix(reserveAcc.Bytes())...) +} + +// GetPoolBatchKey returns kv indexing key of the pool batch indexed by pool id +func GetPoolBatchKey(poolID uint64) []byte { + key := make([]byte, 9) + key[0] = PoolBatchKeyPrefix[0] + copy(key[1:9], sdk.Uint64ToBigEndian(poolID)) + return key +} + +// GetPoolBatchDepositMsgStatesPrefix returns prefix of deposit message states in the pool's latest batch for iteration +func GetPoolBatchDepositMsgStatesPrefix(poolID uint64) []byte { + key := make([]byte, 9) + key[0] = PoolBatchDepositMsgStateIndexKeyPrefix[0] + copy(key[1:9], sdk.Uint64ToBigEndian(poolID)) + return key +} + +// GetPoolBatchWithdrawMsgsPrefix returns prefix of withdraw message states in the pool's latest batch for iteration +func GetPoolBatchWithdrawMsgsPrefix(poolID uint64) []byte { + key := make([]byte, 9) + key[0] = PoolBatchWithdrawMsgStateIndexKeyPrefix[0] + copy(key[1:9], sdk.Uint64ToBigEndian(poolID)) + return key +} + +// GetPoolBatchSwapMsgStatesPrefix returns prefix of swap message states in the pool's latest batch for iteration +func GetPoolBatchSwapMsgStatesPrefix(poolID uint64) []byte { + key := make([]byte, 9) + key[0] = PoolBatchSwapMsgStateIndexKeyPrefix[0] + copy(key[1:9], sdk.Uint64ToBigEndian(poolID)) + return key +} + +// GetPoolBatchDepositMsgStateIndexKey returns kv indexing key of the latest index value of the msg index +func GetPoolBatchDepositMsgStateIndexKey(poolID, msgIndex uint64) []byte { + key := make([]byte, 17) + key[0] = PoolBatchDepositMsgStateIndexKeyPrefix[0] + copy(key[1:9], sdk.Uint64ToBigEndian(poolID)) + copy(key[9:17], sdk.Uint64ToBigEndian(msgIndex)) + return key +} + +// GetPoolBatchWithdrawMsgStateIndexKey returns kv indexing key of the latest index value of the msg index +func GetPoolBatchWithdrawMsgStateIndexKey(poolID, msgIndex uint64) []byte { + key := make([]byte, 17) + key[0] = PoolBatchWithdrawMsgStateIndexKeyPrefix[0] + copy(key[1:9], sdk.Uint64ToBigEndian(poolID)) + copy(key[9:17], sdk.Uint64ToBigEndian(msgIndex)) + return key +} + +// GetPoolBatchSwapMsgStateIndexKey returns kv indexing key of the latest index value of the msg index +func GetPoolBatchSwapMsgStateIndexKey(poolID, msgIndex uint64) []byte { + key := make([]byte, 17) + key[0] = PoolBatchSwapMsgStateIndexKeyPrefix[0] + copy(key[1:9], sdk.Uint64ToBigEndian(poolID)) + copy(key[9:17], sdk.Uint64ToBigEndian(msgIndex)) + return key +} diff --git a/x/liquidity/types/keys_test.go b/x/liquidity/types/keys_test.go new file mode 100644 index 00000000000..f5a94bd9956 --- /dev/null +++ b/x/liquidity/types/keys_test.go @@ -0,0 +1,74 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +type keysTestSuite struct { + suite.Suite +} + +func TestKeysTestSuite(t *testing.T) { + suite.Run(t, new(keysTestSuite)) +} + +func (s *keysTestSuite) TestGetLiquidityPoolKey() { + s.Require().Equal([]byte{0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9}, types.GetPoolKey(9)) + s.Require().Equal([]byte{0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, types.GetPoolKey(0)) +} + +func (s *keysTestSuite) TestGetLiquidityPoolByReserveAccIndexKey() { + len20acc, err := types.GetReserveAcc("poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4", false) + s.Require().NoError(err) + len32acc, err := types.GetReserveAcc("poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4", true) + s.Require().NoError(err) + + s.Require().Equal([]byte{0x12}, types.GetPoolByReserveAccIndexKey(nil)) + s.Require().Equal([]byte{0x12, 0x14, 0xd3, 0x5a, 0xc, 0xc1, 0x6e, 0xe5, 0x98, 0xf9, 0xb, 0x4, 0x4c, 0xe2, 0x96, 0xa4, 0x5, 0xba, 0x9c, 0x38, 0x1e, 0x38}, types.GetPoolByReserveAccIndexKey(len20acc)) + s.Require().Equal([]byte{0x12, 0x20, 0x87, 0xec, 0x7d, 0x8f, 0xca, 0xee, 0xb0, 0xaa, 0x2, 0x1d, 0xc7, 0xd0, 0x69, 0xb, 0x1e, 0xb8, 0xfb, 0x3e, 0x8e, 0xb1, 0x22, 0x7f, 0x78, 0xae, 0x6c, 0x5e, 0x8a, 0x96, 0xc6, 0x7, 0xc4, 0x98}, types.GetPoolByReserveAccIndexKey(len32acc)) +} + +func (s *keysTestSuite) TestGetLiquidityPoolBatchKey() { + s.Require().Equal([]byte{0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa}, types.GetPoolBatchKey(10)) + s.Require().Equal([]byte{0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, types.GetPoolBatchKey(0)) +} + +func (s *keysTestSuite) TestGetLiquidityPoolBatchDepositMsgsPrefix() { + s.Require().Equal([]byte{0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa}, types.GetPoolBatchDepositMsgStatesPrefix(10)) + s.Require().Equal([]byte{0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, types.GetPoolBatchDepositMsgStatesPrefix(0)) +} + +func (s *keysTestSuite) TestGetLiquidityPoolBatchWithdrawMsgsPrefix() { + s.Require().Equal([]byte{0x32, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa}, types.GetPoolBatchWithdrawMsgsPrefix(10)) + s.Require().Equal([]byte{0x32, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, types.GetPoolBatchWithdrawMsgsPrefix(0)) +} + +func (s *keysTestSuite) TestGetLiquidityPoolBatchSwapMsgsPrefix() { + s.Require().Equal([]byte{0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa}, types.GetPoolBatchSwapMsgStatesPrefix(10)) + s.Require().Equal([]byte{0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, types.GetPoolBatchSwapMsgStatesPrefix(0)) +} + +func (s *keysTestSuite) TestGetLiquidityPoolBatchDepositMsgIndex() { + s.Require().Equal([]byte{0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa}, + types.GetPoolBatchDepositMsgStateIndexKey(10, 10)) + s.Require().Equal([]byte{0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + types.GetPoolBatchDepositMsgStateIndexKey(0, 0)) +} + +func (s *keysTestSuite) TestGetLiquidityPoolBatchWithdrawMsgIndex() { + s.Require().Equal([]byte{0x32, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa}, + types.GetPoolBatchWithdrawMsgStateIndexKey(10, 10)) + s.Require().Equal([]byte{0x32, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + types.GetPoolBatchWithdrawMsgStateIndexKey(0, 0)) +} + +func (s *keysTestSuite) TestGetLiquidityPoolBatchSwapMsgIndex() { + s.Require().Equal([]byte{0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa}, + types.GetPoolBatchSwapMsgStateIndexKey(10, 10)) + s.Require().Equal([]byte{0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + types.GetPoolBatchSwapMsgStateIndexKey(0, 0)) +} diff --git a/x/liquidity/types/liquidity.pb.go b/x/liquidity/types/liquidity.pb.go new file mode 100644 index 00000000000..e2e07a5a59f --- /dev/null +++ b/x/liquidity/types/liquidity.pb.go @@ -0,0 +1,3439 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tendermint/liquidity/v1beta1/liquidity.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + 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 + +// Structure for the pool type to distinguish the characteristics of the reserve pools. +type PoolType struct { + // This is the id of the pool_type that is used as pool_type_id for pool creation. + // In this version, only pool-type-id 1 is supported. + // {"id":1,"name":"ConstantProductLiquidityPool","min_reserve_coin_num":2,"max_reserve_coin_num":2,"description":""} + Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` + // name of the pool type. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` + // minimum number of reserveCoins for LiquidityPoolType, only 2 reserve coins are supported. + MinReserveCoinNum uint32 `protobuf:"varint,3,opt,name=min_reserve_coin_num,json=minReserveCoinNum,proto3" json:"min_reserve_coin_num,omitempty" yaml:"min_reserve_coin_num"` + // maximum number of reserveCoins for LiquidityPoolType, only 2 reserve coins are supported. + MaxReserveCoinNum uint32 `protobuf:"varint,4,opt,name=max_reserve_coin_num,json=maxReserveCoinNum,proto3" json:"max_reserve_coin_num,omitempty" yaml:"max_reserve_coin_num"` + // description of the pool type. + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` +} + +func (m *PoolType) Reset() { *m = PoolType{} } +func (m *PoolType) String() string { return proto.CompactTextString(m) } +func (*PoolType) ProtoMessage() {} +func (*PoolType) Descriptor() ([]byte, []int) { + return fileDescriptor_714a3e326c5b7d34, []int{0} +} +func (m *PoolType) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PoolType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PoolType.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 *PoolType) XXX_Merge(src proto.Message) { + xxx_messageInfo_PoolType.Merge(m, src) +} +func (m *PoolType) XXX_Size() int { + return m.Size() +} +func (m *PoolType) XXX_DiscardUnknown() { + xxx_messageInfo_PoolType.DiscardUnknown(m) +} + +var xxx_messageInfo_PoolType proto.InternalMessageInfo + +// Params defines the parameters for the liquidity module. +type Params struct { + // list of available pool types + PoolTypes []PoolType `protobuf:"bytes,1,rep,name=pool_types,json=poolTypes,proto3" json:"pool_types" yaml:"pool_types"` + // Minimum number of coins to be deposited to the liquidity pool on pool creation. + MinInitDepositAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=min_init_deposit_amount,json=minInitDepositAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"min_init_deposit_amount" yaml:"min_init_deposit_amount"` + // Initial mint amount of pool coins upon pool creation. + InitPoolCoinMintAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=init_pool_coin_mint_amount,json=initPoolCoinMintAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"init_pool_coin_mint_amount" yaml:"init_pool_coin_mint_amount"` + // Limit the size of each liquidity pool to minimize risk. In development, set to 0 for no limit. In production, set a limit. + MaxReserveCoinAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=max_reserve_coin_amount,json=maxReserveCoinAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_reserve_coin_amount" yaml:"max_reserve_coin_amount"` + // Fee paid to create a Liquidity Pool. Set a fee to prevent spamming. + PoolCreationFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,5,rep,name=pool_creation_fee,json=poolCreationFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"pool_creation_fee" yaml:"pool_creation_fee"` + // Swap fee rate for every executed swap. + SwapFeeRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=swap_fee_rate,json=swapFeeRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"swap_fee_rate" yaml:"swap_fee_rate"` + // Reserve coin withdrawal with less proportion by withdrawFeeRate. + WithdrawFeeRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,7,opt,name=withdraw_fee_rate,json=withdrawFeeRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"withdraw_fee_rate" yaml:"withdraw_fee_rate"` + // Maximum ratio of reserve coins that can be ordered at a swap order. + MaxOrderAmountRatio github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,8,opt,name=max_order_amount_ratio,json=maxOrderAmountRatio,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"max_order_amount_ratio" yaml:"max_order_amount_ratio"` + // The smallest unit batch height for every liquidity pool. + UnitBatchHeight uint32 `protobuf:"varint,9,opt,name=unit_batch_height,json=unitBatchHeight,proto3" json:"unit_batch_height,omitempty" yaml:"unit_batch_height"` + // Circuit breaker enables or disables transaction messages in liquidity module. + CircuitBreakerEnabled bool `protobuf:"varint,10,opt,name=circuit_breaker_enabled,json=circuitBreakerEnabled,proto3" json:"circuit_breaker_enabled,omitempty" yaml:"circuit_breaker_enabled"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_714a3e326c5b7d34, []int{1} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +// Pool defines the liquidity pool that contains pool information. +type Pool struct { + // id of the pool + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id" yaml:"id"` + // id of the pool_type + TypeId uint32 `protobuf:"varint,2,opt,name=type_id,json=typeId,proto3" json:"type_id,omitempty" yaml:"type_id"` + // denoms of reserve coin pair of the pool + ReserveCoinDenoms []string `protobuf:"bytes,3,rep,name=reserve_coin_denoms,json=reserveCoinDenoms,proto3" json:"reserve_coin_denoms,omitempty" yaml:"reserve_coin_denoms"` + // reserve account address of the pool + ReserveAccountAddress string `protobuf:"bytes,4,opt,name=reserve_account_address,json=reserveAccountAddress,proto3" json:"reserve_account_address,omitempty" yaml:"reserve_account_address"` + // denom of pool coin of the pool + PoolCoinDenom string `protobuf:"bytes,5,opt,name=pool_coin_denom,json=poolCoinDenom,proto3" json:"pool_coin_denom,omitempty" yaml:"pool_coin_denom"` +} + +func (m *Pool) Reset() { *m = Pool{} } +func (m *Pool) String() string { return proto.CompactTextString(m) } +func (*Pool) ProtoMessage() {} +func (*Pool) Descriptor() ([]byte, []int) { + return fileDescriptor_714a3e326c5b7d34, []int{2} +} +func (m *Pool) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Pool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Pool.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 *Pool) XXX_Merge(src proto.Message) { + xxx_messageInfo_Pool.Merge(m, src) +} +func (m *Pool) XXX_Size() int { + return m.Size() +} +func (m *Pool) XXX_DiscardUnknown() { + xxx_messageInfo_Pool.DiscardUnknown(m) +} + +var xxx_messageInfo_Pool proto.InternalMessageInfo + +// Metadata for the state of each pool for invariant checking after genesis export or import. +type PoolMetadata struct { + // id of the pool + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id" yaml:"pool_id"` + // pool coin issued at the pool + PoolCoinTotalSupply types.Coin `protobuf:"bytes,2,opt,name=pool_coin_total_supply,json=poolCoinTotalSupply,proto3" json:"pool_coin_total_supply" yaml:"pool_coin_total_supply"` + // reserve coins deposited in the pool + ReserveCoins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=reserve_coins,json=reserveCoins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"reserve_coins" yaml:"reserve_coins"` +} + +func (m *PoolMetadata) Reset() { *m = PoolMetadata{} } +func (m *PoolMetadata) String() string { return proto.CompactTextString(m) } +func (*PoolMetadata) ProtoMessage() {} +func (*PoolMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_714a3e326c5b7d34, []int{3} +} +func (m *PoolMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PoolMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PoolMetadata.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 *PoolMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_PoolMetadata.Merge(m, src) +} +func (m *PoolMetadata) XXX_Size() int { + return m.Size() +} +func (m *PoolMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_PoolMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_PoolMetadata proto.InternalMessageInfo + +// PoolBatch defines the batch or batches of a given liquidity pool that contains indexes of deposit, withdraw, and swap messages. +// Index param increments by 1 if the pool id is same. +type PoolBatch struct { + // id of the pool + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id" yaml:"pool_id"` + // index of this batch + Index uint64 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty" yaml:"index"` + // height where this batch is started + BeginHeight int64 `protobuf:"varint,3,opt,name=begin_height,json=beginHeight,proto3" json:"begin_height,omitempty" yaml:"begin_height"` + // last index of DepositMsgStates + DepositMsgIndex uint64 `protobuf:"varint,4,opt,name=deposit_msg_index,json=depositMsgIndex,proto3" json:"deposit_msg_index,omitempty" yaml:"deposit_msg_index"` + // last index of WithdrawMsgStates + WithdrawMsgIndex uint64 `protobuf:"varint,5,opt,name=withdraw_msg_index,json=withdrawMsgIndex,proto3" json:"withdraw_msg_index,omitempty" yaml:"withdraw_msg_index"` + // last index of SwapMsgStates + SwapMsgIndex uint64 `protobuf:"varint,6,opt,name=swap_msg_index,json=swapMsgIndex,proto3" json:"swap_msg_index,omitempty" yaml:"swap_msg_index"` + // true if executed, false if not executed + Executed bool `protobuf:"varint,7,opt,name=executed,proto3" json:"executed,omitempty" yaml:"executed"` +} + +func (m *PoolBatch) Reset() { *m = PoolBatch{} } +func (m *PoolBatch) String() string { return proto.CompactTextString(m) } +func (*PoolBatch) ProtoMessage() {} +func (*PoolBatch) Descriptor() ([]byte, []int) { + return fileDescriptor_714a3e326c5b7d34, []int{4} +} +func (m *PoolBatch) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PoolBatch) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PoolBatch.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 *PoolBatch) XXX_Merge(src proto.Message) { + xxx_messageInfo_PoolBatch.Merge(m, src) +} +func (m *PoolBatch) XXX_Size() int { + return m.Size() +} +func (m *PoolBatch) XXX_DiscardUnknown() { + xxx_messageInfo_PoolBatch.DiscardUnknown(m) +} + +var xxx_messageInfo_PoolBatch proto.InternalMessageInfo + +// DepositMsgState defines the state of deposit message that contains state information as it is processed in the next batch or batches. +type DepositMsgState struct { + // height where this message is appended to the batch + MsgHeight int64 `protobuf:"varint,1,opt,name=msg_height,json=msgHeight,proto3" json:"msg_height,omitempty" yaml:"msg_height"` + // index of this deposit message in this liquidity pool + MsgIndex uint64 `protobuf:"varint,2,opt,name=msg_index,json=msgIndex,proto3" json:"msg_index,omitempty" yaml:"msg_index"` + // true if executed on this batch, false if not executed + Executed bool `protobuf:"varint,3,opt,name=executed,proto3" json:"executed,omitempty" yaml:"executed"` + // true if executed successfully on this batch, false if failed + Succeeded bool `protobuf:"varint,4,opt,name=succeeded,proto3" json:"succeeded,omitempty" yaml:"succeeded"` + // true if ready to be deleted on kvstore, false if not ready to be deleted + ToBeDeleted bool `protobuf:"varint,5,opt,name=to_be_deleted,json=toBeDeleted,proto3" json:"to_be_deleted,omitempty" yaml:"to_be_deleted"` + // MsgDepositWithinBatch + Msg *MsgDepositWithinBatch `protobuf:"bytes,6,opt,name=msg,proto3" json:"msg,omitempty" yaml:"msg"` +} + +func (m *DepositMsgState) Reset() { *m = DepositMsgState{} } +func (m *DepositMsgState) String() string { return proto.CompactTextString(m) } +func (*DepositMsgState) ProtoMessage() {} +func (*DepositMsgState) Descriptor() ([]byte, []int) { + return fileDescriptor_714a3e326c5b7d34, []int{5} +} +func (m *DepositMsgState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DepositMsgState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DepositMsgState.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 *DepositMsgState) XXX_Merge(src proto.Message) { + xxx_messageInfo_DepositMsgState.Merge(m, src) +} +func (m *DepositMsgState) XXX_Size() int { + return m.Size() +} +func (m *DepositMsgState) XXX_DiscardUnknown() { + xxx_messageInfo_DepositMsgState.DiscardUnknown(m) +} + +var xxx_messageInfo_DepositMsgState proto.InternalMessageInfo + +// WithdrawMsgState defines the state of the withdraw message that contains state information as the message is processed in the next batch or batches. +type WithdrawMsgState struct { + // height where this message is appended to the batch + MsgHeight int64 `protobuf:"varint,1,opt,name=msg_height,json=msgHeight,proto3" json:"msg_height,omitempty" yaml:"msg_height"` + // index of this withdraw message in this liquidity pool + MsgIndex uint64 `protobuf:"varint,2,opt,name=msg_index,json=msgIndex,proto3" json:"msg_index,omitempty" yaml:"msg_index"` + // true if executed on this batch, false if not executed + Executed bool `protobuf:"varint,3,opt,name=executed,proto3" json:"executed,omitempty" yaml:"executed"` + // true if executed successfully on this batch, false if failed + Succeeded bool `protobuf:"varint,4,opt,name=succeeded,proto3" json:"succeeded,omitempty" yaml:"succeeded"` + // true if ready to be deleted on kvstore, false if not ready to be deleted + ToBeDeleted bool `protobuf:"varint,5,opt,name=to_be_deleted,json=toBeDeleted,proto3" json:"to_be_deleted,omitempty" yaml:"to_be_deleted"` + // MsgWithdrawWithinBatch + Msg *MsgWithdrawWithinBatch `protobuf:"bytes,6,opt,name=msg,proto3" json:"msg,omitempty" yaml:"msg"` +} + +func (m *WithdrawMsgState) Reset() { *m = WithdrawMsgState{} } +func (m *WithdrawMsgState) String() string { return proto.CompactTextString(m) } +func (*WithdrawMsgState) ProtoMessage() {} +func (*WithdrawMsgState) Descriptor() ([]byte, []int) { + return fileDescriptor_714a3e326c5b7d34, []int{6} +} +func (m *WithdrawMsgState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WithdrawMsgState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WithdrawMsgState.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 *WithdrawMsgState) XXX_Merge(src proto.Message) { + xxx_messageInfo_WithdrawMsgState.Merge(m, src) +} +func (m *WithdrawMsgState) XXX_Size() int { + return m.Size() +} +func (m *WithdrawMsgState) XXX_DiscardUnknown() { + xxx_messageInfo_WithdrawMsgState.DiscardUnknown(m) +} + +var xxx_messageInfo_WithdrawMsgState proto.InternalMessageInfo + +// SwapMsgState defines the state of the swap message that contains state information as the message is processed in the next batch or batches. +type SwapMsgState struct { + // height where this message is appended to the batch + MsgHeight int64 `protobuf:"varint,1,opt,name=msg_height,json=msgHeight,proto3" json:"msg_height,omitempty" yaml:"msg_height"` + // index of this swap message in this liquidity pool + MsgIndex uint64 `protobuf:"varint,2,opt,name=msg_index,json=msgIndex,proto3" json:"msg_index,omitempty" yaml:"msg_index"` + // true if executed on this batch, false if not executed + Executed bool `protobuf:"varint,3,opt,name=executed,proto3" json:"executed,omitempty" yaml:"executed"` + // true if executed successfully on this batch, false if failed + Succeeded bool `protobuf:"varint,4,opt,name=succeeded,proto3" json:"succeeded,omitempty" yaml:"succeeded"` + // true if ready to be deleted on kvstore, false if not ready to be deleted + ToBeDeleted bool `protobuf:"varint,5,opt,name=to_be_deleted,json=toBeDeleted,proto3" json:"to_be_deleted,omitempty" yaml:"to_be_deleted"` + // swap orders are cancelled when current height is equal to or higher than ExpiryHeight + OrderExpiryHeight int64 `protobuf:"varint,6,opt,name=order_expiry_height,json=orderExpiryHeight,proto3" json:"order_expiry_height,omitempty" yaml:"order_expiry_height"` + // offer coin exchanged until now + ExchangedOfferCoin types.Coin `protobuf:"bytes,7,opt,name=exchanged_offer_coin,json=exchangedOfferCoin,proto3" json:"exchanged_offer_coin" yaml:"exchanged_offer_coin"` + // offer coin currently remaining to be exchanged + RemainingOfferCoin types.Coin `protobuf:"bytes,8,opt,name=remaining_offer_coin,json=remainingOfferCoin,proto3" json:"remaining_offer_coin" yaml:"remaining_offer_coin"` + // reserve fee for pays fee in half offer coin + ReservedOfferCoinFee types.Coin `protobuf:"bytes,9,opt,name=reserved_offer_coin_fee,json=reservedOfferCoinFee,proto3" json:"reserved_offer_coin_fee" yaml:"reserved_offer_coin_fee"` + // MsgSwapWithinBatch + Msg *MsgSwapWithinBatch `protobuf:"bytes,10,opt,name=msg,proto3" json:"msg,omitempty" yaml:"msg"` +} + +func (m *SwapMsgState) Reset() { *m = SwapMsgState{} } +func (m *SwapMsgState) String() string { return proto.CompactTextString(m) } +func (*SwapMsgState) ProtoMessage() {} +func (*SwapMsgState) Descriptor() ([]byte, []int) { + return fileDescriptor_714a3e326c5b7d34, []int{7} +} +func (m *SwapMsgState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SwapMsgState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SwapMsgState.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 *SwapMsgState) XXX_Merge(src proto.Message) { + xxx_messageInfo_SwapMsgState.Merge(m, src) +} +func (m *SwapMsgState) XXX_Size() int { + return m.Size() +} +func (m *SwapMsgState) XXX_DiscardUnknown() { + xxx_messageInfo_SwapMsgState.DiscardUnknown(m) +} + +var xxx_messageInfo_SwapMsgState proto.InternalMessageInfo + +func init() { + proto.RegisterType((*PoolType)(nil), "tendermint.liquidity.v1beta1.PoolType") + proto.RegisterType((*Params)(nil), "tendermint.liquidity.v1beta1.Params") + proto.RegisterType((*Pool)(nil), "tendermint.liquidity.v1beta1.Pool") + proto.RegisterType((*PoolMetadata)(nil), "tendermint.liquidity.v1beta1.PoolMetadata") + proto.RegisterType((*PoolBatch)(nil), "tendermint.liquidity.v1beta1.PoolBatch") + proto.RegisterType((*DepositMsgState)(nil), "tendermint.liquidity.v1beta1.DepositMsgState") + proto.RegisterType((*WithdrawMsgState)(nil), "tendermint.liquidity.v1beta1.WithdrawMsgState") + proto.RegisterType((*SwapMsgState)(nil), "tendermint.liquidity.v1beta1.SwapMsgState") +} + +func init() { + proto.RegisterFile("tendermint/liquidity/v1beta1/liquidity.proto", fileDescriptor_714a3e326c5b7d34) +} + +var fileDescriptor_714a3e326c5b7d34 = []byte{ + // 1950 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x58, 0xcd, 0x6f, 0xdb, 0xc8, + 0x15, 0x37, 0x25, 0x59, 0x96, 0xc6, 0x5f, 0x31, 0xed, 0x38, 0x4a, 0xb2, 0x91, 0x94, 0x69, 0xb3, + 0x35, 0xb6, 0xb1, 0x2c, 0x4b, 0xb2, 0x63, 0xbb, 0xbd, 0x90, 0xfe, 0xd8, 0xb5, 0x50, 0x77, 0x53, + 0x26, 0xed, 0x36, 0x9b, 0x5d, 0x68, 0x29, 0x72, 0x24, 0xb1, 0x16, 0x49, 0x85, 0x1c, 0xd9, 0x72, + 0x8b, 0x05, 0x7a, 0xdc, 0x43, 0x0b, 0x14, 0x42, 0x0f, 0x45, 0x0b, 0xb4, 0x0b, 0x03, 0xc5, 0x02, + 0x2d, 0xf6, 0xd4, 0xf6, 0x0f, 0xe8, 0x2d, 0xc7, 0x1c, 0x8b, 0x1e, 0xd4, 0x36, 0xb9, 0x14, 0x45, + 0xd1, 0x83, 0xfe, 0x82, 0x62, 0x3e, 0x28, 0xd2, 0x36, 0x6d, 0x6d, 0x00, 0x1d, 0xe3, 0x8b, 0xa9, + 0x37, 0xef, 0xe3, 0xf7, 0xde, 0xfb, 0xcd, 0x9b, 0x21, 0xc1, 0x7d, 0x8c, 0x2c, 0x1d, 0x39, 0xa6, + 0x61, 0xe1, 0x95, 0xa6, 0xf1, 0xac, 0x6d, 0xe8, 0x06, 0x3e, 0x59, 0x39, 0x5a, 0xad, 0x22, 0xac, + 0xae, 0xfa, 0x92, 0x5c, 0xcb, 0xb1, 0xb1, 0x2d, 0xbe, 0xe5, 0x6b, 0xe7, 0xfc, 0x35, 0xae, 0x7d, + 0xeb, 0xde, 0x95, 0xbe, 0x70, 0x87, 0x39, 0xb9, 0xb5, 0x50, 0xb7, 0xeb, 0x36, 0x7d, 0x5c, 0x21, + 0x4f, 0x5c, 0x7a, 0x43, 0xb3, 0x5d, 0xd3, 0x76, 0x2b, 0x6c, 0x41, 0xb3, 0x0d, 0x8b, 0x2f, 0xb0, + 0x7f, 0xda, 0x72, 0x1d, 0x59, 0xcb, 0x76, 0x0b, 0x59, 0x6a, 0xcb, 0x38, 0x2a, 0xac, 0xd8, 0x2d, + 0x6c, 0xd8, 0x96, 0xbb, 0xa2, 0x5a, 0x96, 0x8d, 0x55, 0xfa, 0xcc, 0x14, 0xe1, 0x67, 0x51, 0x90, + 0x78, 0x68, 0xdb, 0xcd, 0xc7, 0x27, 0x2d, 0x24, 0xe6, 0x40, 0xc4, 0xd0, 0x53, 0x42, 0x56, 0x58, + 0x9a, 0x96, 0xd3, 0x5d, 0x69, 0xa6, 0x1c, 0x85, 0xab, 0xf0, 0x34, 0x12, 0x6f, 0x1b, 0x16, 0x2e, + 0x16, 0xfa, 0xbd, 0x4c, 0xf2, 0x44, 0x35, 0x9b, 0x5b, 0xd0, 0xd0, 0xa1, 0x12, 0x31, 0x74, 0x71, + 0x0f, 0xc4, 0x2c, 0xd5, 0x44, 0xa9, 0x48, 0x56, 0x58, 0x4a, 0xca, 0x85, 0xae, 0x94, 0x2d, 0xa7, + 0xe1, 0xb6, 0x6d, 0xb9, 0x58, 0xb5, 0xf0, 0x43, 0xc7, 0xd6, 0xdb, 0x1a, 0xfe, 0x8e, 0x97, 0x1a, + 0x89, 0x02, 0xfb, 0xbd, 0xcc, 0x24, 0xf3, 0x41, 0x0c, 0xa1, 0x42, 0xed, 0x45, 0x15, 0x2c, 0x98, + 0x86, 0x55, 0x71, 0x90, 0x8b, 0x9c, 0x23, 0x54, 0x21, 0xe9, 0x54, 0xac, 0xb6, 0x99, 0x8a, 0x52, + 0x24, 0x79, 0x86, 0xa4, 0x70, 0x06, 0xc9, 0x6d, 0xe6, 0x25, 0xcc, 0x0c, 0x2a, 0x73, 0xa6, 0x61, + 0x29, 0x4c, 0xba, 0x6d, 0x1b, 0xd6, 0x77, 0xdb, 0x26, 0x0d, 0xa1, 0x76, 0x2e, 0x86, 0x88, 0x0d, + 0x0f, 0x11, 0x62, 0x46, 0x42, 0xa8, 0x9d, 0x73, 0x21, 0x36, 0xc0, 0xa4, 0x8e, 0x5c, 0xcd, 0x31, + 0x68, 0xb1, 0x53, 0xe3, 0xb4, 0x28, 0x8b, 0xfd, 0x5e, 0x46, 0x64, 0x8e, 0x02, 0x8b, 0x50, 0x09, + 0xaa, 0x6e, 0xc5, 0xfe, 0xfd, 0x79, 0x46, 0x80, 0x7f, 0x9e, 0x04, 0xf1, 0x87, 0xaa, 0xa3, 0x9a, + 0xae, 0xf8, 0x09, 0x00, 0x2d, 0xdb, 0x6e, 0x56, 0xf0, 0x49, 0x0b, 0xb9, 0x29, 0x21, 0x1b, 0x5d, + 0x9a, 0x2c, 0xbc, 0x9d, 0xbb, 0x8a, 0x4e, 0x39, 0xaf, 0x89, 0xf2, 0xcd, 0xe7, 0xbd, 0xcc, 0x58, + 0xbf, 0x97, 0x99, 0x63, 0x51, 0x7d, 0x3f, 0x50, 0x49, 0xb6, 0xb8, 0x92, 0x2b, 0xfe, 0x4e, 0x00, + 0x37, 0x48, 0xf1, 0x0c, 0xcb, 0xc0, 0x15, 0x1d, 0xb5, 0x6c, 0xd7, 0xc0, 0x15, 0xd5, 0xb4, 0xdb, + 0x16, 0xe6, 0xed, 0x6c, 0x74, 0xa5, 0xeb, 0xe5, 0x24, 0x5c, 0xcd, 0xd3, 0x3f, 0x78, 0x1a, 0x99, + 0x70, 0xf5, 0xc3, 0xdc, 0xbe, 0x85, 0x89, 0xff, 0xbf, 0xf7, 0x32, 0x6f, 0xd7, 0x0d, 0xdc, 0x68, + 0x57, 0x73, 0x9a, 0x6d, 0xae, 0x30, 0x36, 0xf2, 0x7f, 0xcb, 0xae, 0x7e, 0xb8, 0x42, 0x23, 0x12, + 0xed, 0x7e, 0x2f, 0x93, 0xf6, 0x7b, 0x15, 0x12, 0x0e, 0x2a, 0xa4, 0xf9, 0xfb, 0x96, 0x81, 0x77, + 0x98, 0x5c, 0xa2, 0x62, 0xf1, 0x0b, 0x01, 0xdc, 0xa2, 0xea, 0x34, 0x03, 0x5a, 0x79, 0x92, 0xba, + 0x07, 0x32, 0x4a, 0x41, 0x1e, 0x8e, 0x0c, 0xe4, 0x5d, 0x4e, 0xed, 0x4b, 0x23, 0x42, 0x65, 0x91, + 0x2c, 0x92, 0x3a, 0x93, 0x8e, 0x1f, 0x18, 0x96, 0x87, 0xf4, 0xf7, 0xa4, 0x96, 0xe7, 0x59, 0xc2, + 0x61, 0xc6, 0x28, 0x4c, 0xab, 0x2b, 0xdd, 0x2e, 0xcf, 0x7a, 0x30, 0x47, 0x57, 0xd1, 0xf0, 0xa0, + 0xa4, 0xa2, 0x67, 0xd8, 0xc9, 0x71, 0xbe, 0x10, 0xc0, 0x1c, 0x4b, 0xcd, 0x41, 0x74, 0x08, 0x54, + 0x6a, 0x08, 0xa5, 0xc6, 0x29, 0xbb, 0x6e, 0xe6, 0x58, 0xa8, 0x5c, 0x55, 0x75, 0xd1, 0x80, 0x54, + 0xc4, 0x58, 0xfe, 0x4c, 0xe8, 0x4a, 0x9b, 0xe5, 0x6f, 0x3e, 0xfd, 0x09, 0xd4, 0x91, 0x65, 0x9b, + 0x70, 0x2b, 0x0b, 0xdb, 0x2a, 0xb6, 0x4d, 0x78, 0x3f, 0x0b, 0x79, 0xc0, 0xad, 0xac, 0x9f, 0x1b, + 0xfc, 0xf4, 0xe3, 0xd3, 0x48, 0x92, 0x64, 0x46, 0xac, 0x5d, 0xce, 0xc6, 0x54, 0x80, 0x8d, 0xc1, + 0xf0, 0xf0, 0x0f, 0xff, 0xc8, 0x2c, 0x7d, 0x85, 0xbc, 0xa9, 0x2f, 0x65, 0x96, 0xd8, 0x6f, 0x73, + 0xf3, 0x3d, 0x84, 0xc4, 0x9f, 0x0a, 0x60, 0xda, 0x3d, 0x56, 0x5b, 0xc4, 0x55, 0xc5, 0x51, 0x31, + 0x4a, 0xc5, 0x69, 0xc1, 0x3f, 0xea, 0x4a, 0xf3, 0xe5, 0x09, 0x98, 0xcf, 0xe5, 0xf3, 0x45, 0xaf, + 0xd0, 0x3b, 0x48, 0x7b, 0x8d, 0x42, 0xef, 0x20, 0xad, 0xdf, 0xcb, 0x2c, 0x30, 0xd8, 0x67, 0x42, + 0x40, 0x65, 0x92, 0xfc, 0xde, 0x43, 0x48, 0x51, 0x31, 0x12, 0x7f, 0x26, 0x80, 0xb9, 0x63, 0x03, + 0x37, 0x74, 0x47, 0x3d, 0xf6, 0x61, 0x4c, 0x50, 0x18, 0x9f, 0x8c, 0x08, 0x06, 0xaf, 0xde, 0x85, + 0x30, 0x50, 0x99, 0xf5, 0x64, 0x1e, 0x9c, 0x5f, 0x0b, 0x60, 0x91, 0xf0, 0xc2, 0x76, 0x74, 0xe4, + 0x70, 0x42, 0x10, 0x5d, 0xc3, 0x4e, 0x25, 0x28, 0x26, 0x34, 0x22, 0x4c, 0x77, 0x7c, 0x0e, 0x5e, + 0x8c, 0x05, 0x95, 0x79, 0x53, 0xed, 0xbc, 0x4f, 0xe4, 0x8c, 0x7c, 0x0a, 0x91, 0x8a, 0x4f, 0xc0, + 0x5c, 0x9b, 0x6c, 0xb0, 0xaa, 0x8a, 0xb5, 0x46, 0xa5, 0x81, 0x8c, 0x7a, 0x03, 0xa7, 0x92, 0x74, + 0x04, 0x2f, 0x87, 0x9d, 0x37, 0x3c, 0xef, 0x0b, 0x36, 0x50, 0x99, 0x25, 0x32, 0x99, 0x88, 0xde, + 0xa3, 0x12, 0xd1, 0x04, 0x37, 0x34, 0xc3, 0xd1, 0xda, 0x44, 0xd3, 0x41, 0xea, 0x21, 0x72, 0x2a, + 0xc8, 0x52, 0xab, 0x4d, 0xa4, 0xa7, 0x40, 0x56, 0x58, 0x4a, 0xc8, 0x6b, 0x5d, 0xe9, 0x5a, 0x79, + 0x02, 0xd6, 0xd4, 0xa6, 0x8b, 0xe0, 0x69, 0x24, 0x56, 0xb5, 0xed, 0xa6, 0xbf, 0x95, 0x2e, 0xb1, + 0x85, 0xca, 0x75, 0xbe, 0x22, 0xb3, 0x85, 0x5d, 0x26, 0xdf, 0x4a, 0xfc, 0xea, 0xf3, 0xcc, 0x18, + 0x1d, 0xdb, 0xbf, 0x8d, 0x81, 0x18, 0x19, 0x0a, 0x62, 0x69, 0x70, 0x7a, 0xc6, 0xe4, 0xaf, 0x9f, + 0xcb, 0x66, 0xbd, 0xf4, 0x9f, 0x5e, 0x26, 0x62, 0xe8, 0x17, 0xcf, 0xd0, 0x6f, 0x83, 0x09, 0x52, + 0xd5, 0x8a, 0xa1, 0xd3, 0xb9, 0x3b, 0x2d, 0x7f, 0x2d, 0xac, 0x10, 0x33, 0xcc, 0x88, 0x6b, 0x42, + 0x25, 0x4e, 0x9e, 0xf6, 0x75, 0xb1, 0x06, 0xe6, 0xcf, 0x0c, 0x00, 0xba, 0x43, 0xdd, 0x54, 0x34, + 0x1b, 0x5d, 0x4a, 0xca, 0xeb, 0x64, 0x38, 0xce, 0x3f, 0x65, 0xdb, 0xf6, 0x87, 0xf0, 0x3e, 0x7b, + 0x78, 0x02, 0x3f, 0xee, 0xf7, 0x32, 0xb7, 0x98, 0xc3, 0x10, 0x63, 0xa8, 0xcc, 0x39, 0xfe, 0xe8, + 0xd8, 0xa1, 0x32, 0x7a, 0x5c, 0x78, 0xba, 0xaa, 0xa6, 0xd1, 0x46, 0xab, 0xba, 0xee, 0x20, 0xd7, + 0xe5, 0x23, 0xae, 0xde, 0x95, 0xe4, 0xf2, 0x0a, 0x64, 0x64, 0x59, 0x5d, 0xd7, 0xf5, 0x67, 0xc8, + 0xc5, 0xc7, 0xed, 0xc3, 0xa3, 0xfc, 0x8f, 0x7e, 0xac, 0x9d, 0xd4, 0xac, 0x62, 0x4d, 0xaf, 0x3d, + 0xdb, 0x6c, 0x14, 0x8e, 0x1d, 0x77, 0xa3, 0xa8, 0x39, 0x25, 0xa7, 0x66, 0x12, 0xfa, 0xcd, 0x10, + 0xfa, 0x49, 0x9a, 0x26, 0x31, 0x67, 0x7e, 0x43, 0x2e, 0x89, 0x06, 0x95, 0xeb, 0x7c, 0x45, 0x62, + 0x0b, 0xdc, 0x50, 0xfc, 0xb9, 0x00, 0x66, 0xfd, 0xb9, 0x4d, 0x53, 0xe1, 0x47, 0x30, 0xea, 0x4a, + 0xef, 0x95, 0xf7, 0xe8, 0xe8, 0xd9, 0x29, 0xae, 0x49, 0xf9, 0xed, 0xed, 0xd5, 0xf5, 0xdd, 0xdd, + 0xb5, 0xcd, 0x8d, 0xbd, 0xcd, 0xbc, 0x9c, 0x2f, 0x95, 0xb6, 0x77, 0x0b, 0x9b, 0xeb, 0x52, 0x29, + 0xbf, 0x26, 0x4b, 0x9b, 0xdb, 0xc5, 0x8d, 0xd5, 0xdd, 0xe2, 0xc6, 0x46, 0xf1, 0xc1, 0xda, 0xe6, + 0xe6, 0xce, 0xe6, 0xfa, 0x5e, 0x61, 0xef, 0x41, 0x7e, 0xbb, 0xb0, 0x97, 0x2f, 0x48, 0x85, 0xa2, + 0x54, 0x22, 0xf7, 0x97, 0xc5, 0xe0, 0x24, 0x1b, 0xc4, 0x82, 0xca, 0x74, 0x8b, 0x9f, 0x0c, 0xb4, + 0x64, 0x94, 0x20, 0x02, 0x25, 0xc8, 0x5f, 0x63, 0x60, 0x8a, 0x10, 0xe4, 0x00, 0x61, 0x55, 0x57, + 0xb1, 0x2a, 0xbe, 0x0b, 0x26, 0xa8, 0xf5, 0x80, 0x2d, 0xb9, 0x30, 0xb6, 0x78, 0x3a, 0x7e, 0xf7, + 0xb9, 0x00, 0x2a, 0x71, 0xf2, 0xb4, 0xaf, 0x8b, 0xff, 0x15, 0xc0, 0xa2, 0x8f, 0x03, 0xdb, 0x58, + 0x6d, 0x56, 0xdc, 0x76, 0xab, 0xd5, 0x3c, 0xa1, 0x5c, 0xba, 0x72, 0xaa, 0xff, 0x46, 0xe8, 0x4a, + 0x6e, 0xb9, 0x16, 0x18, 0xea, 0x23, 0x29, 0x50, 0xd8, 0x99, 0x00, 0x3f, 0x3d, 0x8d, 0x24, 0xbc, + 0x03, 0x81, 0x9f, 0x07, 0x77, 0xce, 0x57, 0x31, 0x88, 0x1e, 0x2a, 0xf3, 0x5e, 0x31, 0x1f, 0x13, + 0xf1, 0x23, 0x2a, 0x15, 0xff, 0x27, 0x80, 0xe9, 0x20, 0x61, 0x19, 0xcf, 0xaf, 0xcc, 0xf2, 0x4b, + 0xa1, 0x2b, 0x55, 0xcb, 0x8f, 0x83, 0x67, 0x97, 0xb7, 0x1b, 0x42, 0x81, 0xde, 0xcf, 0x9e, 0xd7, + 0x7c, 0x72, 0x56, 0xb3, 0x70, 0xd5, 0x21, 0xb7, 0x70, 0x71, 0x53, 0xb9, 0xaf, 0x77, 0xc0, 0x4d, + 0x05, 0xb6, 0x9e, 0x1b, 0xe0, 0xd0, 0x1f, 0x63, 0x20, 0x49, 0x38, 0x44, 0x27, 0xde, 0xe8, 0x08, + 0xf4, 0x00, 0x8c, 0x1b, 0x96, 0x8e, 0x3a, 0x94, 0x2e, 0x31, 0xf9, 0xee, 0x05, 0x37, 0xfd, 0x5e, + 0x66, 0xca, 0xbb, 0x18, 0xe9, 0xa8, 0x03, 0x15, 0xa6, 0x2f, 0x1e, 0x80, 0xa9, 0x2a, 0xaa, 0x1b, + 0x96, 0x37, 0xc3, 0xc9, 0x6d, 0x2c, 0x2a, 0xbf, 0x43, 0x46, 0x6c, 0x9c, 0x56, 0x13, 0x9e, 0x46, + 0xc6, 0x3d, 0x0f, 0xf3, 0xcc, 0x43, 0xd0, 0x00, 0x2a, 0x93, 0xf4, 0x27, 0x1f, 0xde, 0x4f, 0xc0, + 0x9c, 0x77, 0x29, 0x34, 0xdd, 0x7a, 0x85, 0x61, 0x8a, 0x51, 0x4c, 0xcb, 0x61, 0x98, 0x52, 0xde, + 0x8d, 0xfa, 0x9c, 0x0d, 0x54, 0x66, 0xb9, 0xec, 0xc0, 0xad, 0xef, 0x53, 0xa4, 0x1f, 0x01, 0x71, + 0x70, 0x6c, 0xfa, 0xbe, 0xc7, 0x2f, 0x29, 0x5b, 0xbf, 0x97, 0xb9, 0x79, 0xee, 0xac, 0x0d, 0x38, + 0xbf, 0xe6, 0x09, 0x07, 0xde, 0x1f, 0x82, 0x19, 0x7a, 0x37, 0xf0, 0x3d, 0xc7, 0xa9, 0xe7, 0x77, + 0xc2, 0x3c, 0x5f, 0x0f, 0x5c, 0x26, 0x02, 0x5e, 0xa7, 0x88, 0x60, 0xe0, 0x71, 0x03, 0x24, 0x50, + 0x07, 0x69, 0x6d, 0x8c, 0x74, 0x7a, 0x89, 0x48, 0xc8, 0x6f, 0x75, 0xa5, 0x78, 0x39, 0x86, 0x9d, + 0x36, 0xea, 0xf7, 0x32, 0xb3, 0xcc, 0x87, 0xa7, 0x02, 0x95, 0x81, 0x76, 0x80, 0x2d, 0x7f, 0x8a, + 0x82, 0xd9, 0x9d, 0x41, 0x1d, 0x1e, 0x61, 0x72, 0x2f, 0x78, 0x17, 0x00, 0x12, 0x93, 0xf7, 0x4b, + 0xa0, 0xfd, 0x5a, 0x0a, 0xef, 0x17, 0x7f, 0x73, 0xf0, 0xd5, 0xa1, 0x92, 0x34, 0xdd, 0x3a, 0xef, + 0x95, 0x0c, 0x92, 0x7e, 0xb6, 0x8c, 0x37, 0xf7, 0xc2, 0xb2, 0xbd, 0xe6, 0x7b, 0xe1, 0x89, 0x26, + 0xcc, 0xb0, 0x24, 0xa3, 0xaf, 0x93, 0xa4, 0xf8, 0x2d, 0x90, 0x74, 0xdb, 0x9a, 0x86, 0x90, 0x8e, + 0x74, 0xca, 0x90, 0x84, 0x7c, 0x27, 0x68, 0xca, 0xa3, 0x0e, 0x74, 0xa0, 0xe2, 0xeb, 0x8b, 0xbb, + 0x60, 0x1a, 0xdb, 0x95, 0x2a, 0xaa, 0xe8, 0xa8, 0x89, 0x48, 0xec, 0x71, 0xea, 0xe0, 0x6e, 0xd0, + 0x01, 0xdf, 0xc3, 0x67, 0xf4, 0xa0, 0x32, 0x89, 0x6d, 0x19, 0xed, 0xb0, 0x5f, 0xe2, 0xf7, 0x41, + 0xd4, 0x74, 0xeb, 0xb4, 0xd3, 0x93, 0x85, 0xe2, 0xd5, 0xaf, 0x65, 0x07, 0x6e, 0x9d, 0x77, 0xe2, + 0x03, 0x03, 0x37, 0x0c, 0x8b, 0x6e, 0x60, 0x79, 0xa6, 0xdf, 0xcb, 0x80, 0x41, 0x7d, 0xa0, 0x42, + 0xfc, 0xc1, 0xbf, 0x44, 0xc1, 0xb5, 0x0f, 0x7c, 0x82, 0xbd, 0x69, 0xdb, 0x88, 0xdb, 0xf6, 0x83, + 0x60, 0xdb, 0x4a, 0x43, 0xdb, 0xe6, 0xb5, 0x62, 0x68, 0xdf, 0x7e, 0x99, 0x00, 0x53, 0x8f, 0xd8, + 0x16, 0x7e, 0xd3, 0xb3, 0x11, 0xf7, 0x4c, 0x05, 0xf3, 0xec, 0xe5, 0x02, 0x75, 0x5a, 0x86, 0x73, + 0xe2, 0xd5, 0x34, 0x4e, 0x6b, 0xba, 0x1a, 0x5e, 0x53, 0x7e, 0xb5, 0x0d, 0xb1, 0x83, 0xca, 0x1c, + 0x95, 0xee, 0x52, 0x21, 0x2f, 0xf2, 0x17, 0x02, 0x58, 0x40, 0x1d, 0xad, 0xa1, 0x5a, 0x75, 0xa4, + 0x57, 0xec, 0x5a, 0x0d, 0x39, 0xf4, 0xe4, 0xa6, 0xd3, 0xf7, 0xca, 0xcb, 0xc5, 0x87, 0x5d, 0xa9, + 0x54, 0xfe, 0xc6, 0x90, 0xab, 0xc5, 0xfa, 0xa5, 0x57, 0xa0, 0xdb, 0x5e, 0xe9, 0x2f, 0xc6, 0x86, + 0x8a, 0x38, 0x10, 0xbf, 0x4f, 0xa4, 0xc4, 0x8c, 0x22, 0x75, 0x90, 0xa9, 0x1a, 0x96, 0x61, 0xd5, + 0x83, 0x48, 0x13, 0x23, 0x41, 0x5a, 0x1a, 0x86, 0x34, 0x2c, 0x36, 0x54, 0xc4, 0x81, 0xd8, 0x47, + 0xfa, 0xa5, 0xff, 0xba, 0x10, 0x4c, 0x8b, 0x7e, 0x6f, 0x48, 0x0e, 0x03, 0xfb, 0xb4, 0x2b, 0x15, + 0xca, 0xf7, 0x86, 0x80, 0x5d, 0xbb, 0x04, 0xea, 0xd9, 0xb7, 0x87, 0xf3, 0xc1, 0xa1, 0xb2, 0xe0, + 0xad, 0x0c, 0xc0, 0xee, 0x21, 0x24, 0x2a, 0x6c, 0x34, 0x00, 0x0a, 0x2d, 0x3f, 0x74, 0x34, 0x90, + 0xdd, 0x3e, 0x6c, 0x2c, 0xc8, 0xdf, 0x7b, 0xfe, 0xaf, 0xf4, 0xd8, 0xf3, 0x97, 0x69, 0xe1, 0xc5, + 0xcb, 0xb4, 0xf0, 0xcf, 0x97, 0x69, 0xe1, 0x17, 0xaf, 0xd2, 0x63, 0x2f, 0x5e, 0xa5, 0xc7, 0xfe, + 0xf6, 0x2a, 0x3d, 0xf6, 0x61, 0x31, 0x70, 0x25, 0xac, 0x3b, 0xea, 0x91, 0x81, 0x4f, 0x96, 0x75, + 0x74, 0xe4, 0x06, 0x3e, 0x05, 0x77, 0x02, 0xcf, 0xf4, 0x8e, 0x58, 0x8d, 0xd3, 0x6f, 0xb6, 0xc5, + 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x61, 0x5d, 0x42, 0xcc, 0x87, 0x16, 0x00, 0x00, +} + +func (this *PoolType) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*PoolType) + if !ok { + that2, ok := that.(PoolType) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Id != that1.Id { + return false + } + if this.Name != that1.Name { + return false + } + if this.MinReserveCoinNum != that1.MinReserveCoinNum { + return false + } + if this.MaxReserveCoinNum != that1.MaxReserveCoinNum { + return false + } + if this.Description != that1.Description { + return false + } + return true +} +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.PoolTypes) != len(that1.PoolTypes) { + return false + } + for i := range this.PoolTypes { + if !this.PoolTypes[i].Equal(&that1.PoolTypes[i]) { + return false + } + } + if !this.MinInitDepositAmount.Equal(that1.MinInitDepositAmount) { + return false + } + if !this.InitPoolCoinMintAmount.Equal(that1.InitPoolCoinMintAmount) { + return false + } + if !this.MaxReserveCoinAmount.Equal(that1.MaxReserveCoinAmount) { + return false + } + if len(this.PoolCreationFee) != len(that1.PoolCreationFee) { + return false + } + for i := range this.PoolCreationFee { + if !this.PoolCreationFee[i].Equal(&that1.PoolCreationFee[i]) { + return false + } + } + if !this.SwapFeeRate.Equal(that1.SwapFeeRate) { + return false + } + if !this.WithdrawFeeRate.Equal(that1.WithdrawFeeRate) { + return false + } + if !this.MaxOrderAmountRatio.Equal(that1.MaxOrderAmountRatio) { + return false + } + if this.UnitBatchHeight != that1.UnitBatchHeight { + return false + } + if this.CircuitBreakerEnabled != that1.CircuitBreakerEnabled { + return false + } + return true +} +func (this *Pool) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Pool) + if !ok { + that2, ok := that.(Pool) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Id != that1.Id { + return false + } + if this.TypeId != that1.TypeId { + return false + } + if len(this.ReserveCoinDenoms) != len(that1.ReserveCoinDenoms) { + return false + } + for i := range this.ReserveCoinDenoms { + if this.ReserveCoinDenoms[i] != that1.ReserveCoinDenoms[i] { + return false + } + } + if this.ReserveAccountAddress != that1.ReserveAccountAddress { + return false + } + if this.PoolCoinDenom != that1.PoolCoinDenom { + return false + } + return true +} +func (this *PoolMetadata) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*PoolMetadata) + if !ok { + that2, ok := that.(PoolMetadata) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.PoolId != that1.PoolId { + return false + } + if !this.PoolCoinTotalSupply.Equal(&that1.PoolCoinTotalSupply) { + return false + } + if len(this.ReserveCoins) != len(that1.ReserveCoins) { + return false + } + for i := range this.ReserveCoins { + if !this.ReserveCoins[i].Equal(&that1.ReserveCoins[i]) { + return false + } + } + return true +} +func (this *PoolBatch) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*PoolBatch) + if !ok { + that2, ok := that.(PoolBatch) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.PoolId != that1.PoolId { + return false + } + if this.Index != that1.Index { + return false + } + if this.BeginHeight != that1.BeginHeight { + return false + } + if this.DepositMsgIndex != that1.DepositMsgIndex { + return false + } + if this.WithdrawMsgIndex != that1.WithdrawMsgIndex { + return false + } + if this.SwapMsgIndex != that1.SwapMsgIndex { + return false + } + if this.Executed != that1.Executed { + return false + } + return true +} +func (m *PoolType) 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 *PoolType) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PoolType) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintLiquidity(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x2a + } + if m.MaxReserveCoinNum != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.MaxReserveCoinNum)) + i-- + dAtA[i] = 0x20 + } + if m.MinReserveCoinNum != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.MinReserveCoinNum)) + i-- + dAtA[i] = 0x18 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintLiquidity(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if m.Id != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.Id)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CircuitBreakerEnabled { + i-- + if m.CircuitBreakerEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x50 + } + if m.UnitBatchHeight != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.UnitBatchHeight)) + i-- + dAtA[i] = 0x48 + } + { + size := m.MaxOrderAmountRatio.Size() + i -= size + if _, err := m.MaxOrderAmountRatio.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + { + size := m.WithdrawFeeRate.Size() + i -= size + if _, err := m.WithdrawFeeRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + { + size := m.SwapFeeRate.Size() + i -= size + if _, err := m.SwapFeeRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.PoolCreationFee) > 0 { + for iNdEx := len(m.PoolCreationFee) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PoolCreationFee[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + { + size := m.MaxReserveCoinAmount.Size() + i -= size + if _, err := m.MaxReserveCoinAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.InitPoolCoinMintAmount.Size() + i -= size + if _, err := m.InitPoolCoinMintAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.MinInitDepositAmount.Size() + i -= size + if _, err := m.MinInitDepositAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.PoolTypes) > 0 { + for iNdEx := len(m.PoolTypes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PoolTypes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Pool) 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 *Pool) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Pool) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PoolCoinDenom) > 0 { + i -= len(m.PoolCoinDenom) + copy(dAtA[i:], m.PoolCoinDenom) + i = encodeVarintLiquidity(dAtA, i, uint64(len(m.PoolCoinDenom))) + i-- + dAtA[i] = 0x2a + } + if len(m.ReserveAccountAddress) > 0 { + i -= len(m.ReserveAccountAddress) + copy(dAtA[i:], m.ReserveAccountAddress) + i = encodeVarintLiquidity(dAtA, i, uint64(len(m.ReserveAccountAddress))) + i-- + dAtA[i] = 0x22 + } + if len(m.ReserveCoinDenoms) > 0 { + for iNdEx := len(m.ReserveCoinDenoms) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ReserveCoinDenoms[iNdEx]) + copy(dAtA[i:], m.ReserveCoinDenoms[iNdEx]) + i = encodeVarintLiquidity(dAtA, i, uint64(len(m.ReserveCoinDenoms[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if m.TypeId != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.TypeId)) + i-- + dAtA[i] = 0x10 + } + if m.Id != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.Id)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *PoolMetadata) 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 *PoolMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PoolMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ReserveCoins) > 0 { + for iNdEx := len(m.ReserveCoins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ReserveCoins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + { + size, err := m.PoolCoinTotalSupply.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.PoolId != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *PoolBatch) 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 *PoolBatch) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PoolBatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Executed { + i-- + if m.Executed { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x38 + } + if m.SwapMsgIndex != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.SwapMsgIndex)) + i-- + dAtA[i] = 0x30 + } + if m.WithdrawMsgIndex != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.WithdrawMsgIndex)) + i-- + dAtA[i] = 0x28 + } + if m.DepositMsgIndex != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.DepositMsgIndex)) + i-- + dAtA[i] = 0x20 + } + if m.BeginHeight != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.BeginHeight)) + i-- + dAtA[i] = 0x18 + } + if m.Index != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x10 + } + if m.PoolId != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *DepositMsgState) 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 *DepositMsgState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DepositMsgState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Msg != nil { + { + size, err := m.Msg.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if m.ToBeDeleted { + i-- + if m.ToBeDeleted { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if m.Succeeded { + i-- + if m.Succeeded { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if m.Executed { + i-- + if m.Executed { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.MsgIndex != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.MsgIndex)) + i-- + dAtA[i] = 0x10 + } + if m.MsgHeight != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.MsgHeight)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *WithdrawMsgState) 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 *WithdrawMsgState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WithdrawMsgState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Msg != nil { + { + size, err := m.Msg.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if m.ToBeDeleted { + i-- + if m.ToBeDeleted { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if m.Succeeded { + i-- + if m.Succeeded { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if m.Executed { + i-- + if m.Executed { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.MsgIndex != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.MsgIndex)) + i-- + dAtA[i] = 0x10 + } + if m.MsgHeight != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.MsgHeight)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *SwapMsgState) 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 *SwapMsgState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SwapMsgState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Msg != nil { + { + size, err := m.Msg.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + { + size, err := m.ReservedOfferCoinFee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + { + size, err := m.RemainingOfferCoin.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + { + size, err := m.ExchangedOfferCoin.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLiquidity(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + if m.OrderExpiryHeight != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.OrderExpiryHeight)) + i-- + dAtA[i] = 0x30 + } + if m.ToBeDeleted { + i-- + if m.ToBeDeleted { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if m.Succeeded { + i-- + if m.Succeeded { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if m.Executed { + i-- + if m.Executed { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.MsgIndex != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.MsgIndex)) + i-- + dAtA[i] = 0x10 + } + if m.MsgHeight != 0 { + i = encodeVarintLiquidity(dAtA, i, uint64(m.MsgHeight)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintLiquidity(dAtA []byte, offset int, v uint64) int { + offset -= sovLiquidity(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PoolType) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != 0 { + n += 1 + sovLiquidity(uint64(m.Id)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovLiquidity(uint64(l)) + } + if m.MinReserveCoinNum != 0 { + n += 1 + sovLiquidity(uint64(m.MinReserveCoinNum)) + } + if m.MaxReserveCoinNum != 0 { + n += 1 + sovLiquidity(uint64(m.MaxReserveCoinNum)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovLiquidity(uint64(l)) + } + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.PoolTypes) > 0 { + for _, e := range m.PoolTypes { + l = e.Size() + n += 1 + l + sovLiquidity(uint64(l)) + } + } + l = m.MinInitDepositAmount.Size() + n += 1 + l + sovLiquidity(uint64(l)) + l = m.InitPoolCoinMintAmount.Size() + n += 1 + l + sovLiquidity(uint64(l)) + l = m.MaxReserveCoinAmount.Size() + n += 1 + l + sovLiquidity(uint64(l)) + if len(m.PoolCreationFee) > 0 { + for _, e := range m.PoolCreationFee { + l = e.Size() + n += 1 + l + sovLiquidity(uint64(l)) + } + } + l = m.SwapFeeRate.Size() + n += 1 + l + sovLiquidity(uint64(l)) + l = m.WithdrawFeeRate.Size() + n += 1 + l + sovLiquidity(uint64(l)) + l = m.MaxOrderAmountRatio.Size() + n += 1 + l + sovLiquidity(uint64(l)) + if m.UnitBatchHeight != 0 { + n += 1 + sovLiquidity(uint64(m.UnitBatchHeight)) + } + if m.CircuitBreakerEnabled { + n += 2 + } + return n +} + +func (m *Pool) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != 0 { + n += 1 + sovLiquidity(uint64(m.Id)) + } + if m.TypeId != 0 { + n += 1 + sovLiquidity(uint64(m.TypeId)) + } + if len(m.ReserveCoinDenoms) > 0 { + for _, s := range m.ReserveCoinDenoms { + l = len(s) + n += 1 + l + sovLiquidity(uint64(l)) + } + } + l = len(m.ReserveAccountAddress) + if l > 0 { + n += 1 + l + sovLiquidity(uint64(l)) + } + l = len(m.PoolCoinDenom) + if l > 0 { + n += 1 + l + sovLiquidity(uint64(l)) + } + return n +} + +func (m *PoolMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovLiquidity(uint64(m.PoolId)) + } + l = m.PoolCoinTotalSupply.Size() + n += 1 + l + sovLiquidity(uint64(l)) + if len(m.ReserveCoins) > 0 { + for _, e := range m.ReserveCoins { + l = e.Size() + n += 1 + l + sovLiquidity(uint64(l)) + } + } + return n +} + +func (m *PoolBatch) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovLiquidity(uint64(m.PoolId)) + } + if m.Index != 0 { + n += 1 + sovLiquidity(uint64(m.Index)) + } + if m.BeginHeight != 0 { + n += 1 + sovLiquidity(uint64(m.BeginHeight)) + } + if m.DepositMsgIndex != 0 { + n += 1 + sovLiquidity(uint64(m.DepositMsgIndex)) + } + if m.WithdrawMsgIndex != 0 { + n += 1 + sovLiquidity(uint64(m.WithdrawMsgIndex)) + } + if m.SwapMsgIndex != 0 { + n += 1 + sovLiquidity(uint64(m.SwapMsgIndex)) + } + if m.Executed { + n += 2 + } + return n +} + +func (m *DepositMsgState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgHeight != 0 { + n += 1 + sovLiquidity(uint64(m.MsgHeight)) + } + if m.MsgIndex != 0 { + n += 1 + sovLiquidity(uint64(m.MsgIndex)) + } + if m.Executed { + n += 2 + } + if m.Succeeded { + n += 2 + } + if m.ToBeDeleted { + n += 2 + } + if m.Msg != nil { + l = m.Msg.Size() + n += 1 + l + sovLiquidity(uint64(l)) + } + return n +} + +func (m *WithdrawMsgState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgHeight != 0 { + n += 1 + sovLiquidity(uint64(m.MsgHeight)) + } + if m.MsgIndex != 0 { + n += 1 + sovLiquidity(uint64(m.MsgIndex)) + } + if m.Executed { + n += 2 + } + if m.Succeeded { + n += 2 + } + if m.ToBeDeleted { + n += 2 + } + if m.Msg != nil { + l = m.Msg.Size() + n += 1 + l + sovLiquidity(uint64(l)) + } + return n +} + +func (m *SwapMsgState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MsgHeight != 0 { + n += 1 + sovLiquidity(uint64(m.MsgHeight)) + } + if m.MsgIndex != 0 { + n += 1 + sovLiquidity(uint64(m.MsgIndex)) + } + if m.Executed { + n += 2 + } + if m.Succeeded { + n += 2 + } + if m.ToBeDeleted { + n += 2 + } + if m.OrderExpiryHeight != 0 { + n += 1 + sovLiquidity(uint64(m.OrderExpiryHeight)) + } + l = m.ExchangedOfferCoin.Size() + n += 1 + l + sovLiquidity(uint64(l)) + l = m.RemainingOfferCoin.Size() + n += 1 + l + sovLiquidity(uint64(l)) + l = m.ReservedOfferCoinFee.Size() + n += 1 + l + sovLiquidity(uint64(l)) + if m.Msg != nil { + l = m.Msg.Size() + n += 1 + l + sovLiquidity(uint64(l)) + } + return n +} + +func sovLiquidity(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozLiquidity(x uint64) (n int) { + return sovLiquidity(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PoolType) 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 ErrIntOverflowLiquidity + } + 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: PoolType: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PoolType: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + m.Id = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Id |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MinReserveCoinNum", wireType) + } + m.MinReserveCoinNum = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MinReserveCoinNum |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxReserveCoinNum", wireType) + } + m.MaxReserveCoinNum = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxReserveCoinNum |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLiquidity(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLiquidity + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 PoolTypes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PoolTypes = append(m.PoolTypes, PoolType{}) + if err := m.PoolTypes[len(m.PoolTypes)-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 MinInitDepositAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinInitDepositAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InitPoolCoinMintAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InitPoolCoinMintAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxReserveCoinAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxReserveCoinAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolCreationFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PoolCreationFee = append(m.PoolCreationFee, types.Coin{}) + if err := m.PoolCreationFee[len(m.PoolCreationFee)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SwapFeeRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.SwapFeeRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WithdrawFeeRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.WithdrawFeeRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxOrderAmountRatio", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxOrderAmountRatio.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnitBatchHeight", wireType) + } + m.UnitBatchHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnitBatchHeight |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CircuitBreakerEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CircuitBreakerEnabled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipLiquidity(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLiquidity + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Pool) 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 ErrIntOverflowLiquidity + } + 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: Pool: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Pool: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + m.Id = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Id |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TypeId", wireType) + } + m.TypeId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TypeId |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReserveCoinDenoms", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReserveCoinDenoms = append(m.ReserveCoinDenoms, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReserveAccountAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReserveAccountAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolCoinDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + 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 ErrInvalidLengthLiquidity + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PoolCoinDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLiquidity(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLiquidity + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PoolMetadata) 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 ErrIntOverflowLiquidity + } + 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: PoolMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PoolMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolCoinTotalSupply", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PoolCoinTotalSupply.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReserveCoins", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReserveCoins = append(m.ReserveCoins, types.Coin{}) + if err := m.ReserveCoins[len(m.ReserveCoins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLiquidity(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLiquidity + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PoolBatch) 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 ErrIntOverflowLiquidity + } + 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: PoolBatch: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PoolBatch: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BeginHeight", wireType) + } + m.BeginHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BeginHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DepositMsgIndex", wireType) + } + m.DepositMsgIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DepositMsgIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WithdrawMsgIndex", wireType) + } + m.WithdrawMsgIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.WithdrawMsgIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SwapMsgIndex", wireType) + } + m.SwapMsgIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SwapMsgIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Executed", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Executed = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipLiquidity(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLiquidity + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DepositMsgState) 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 ErrIntOverflowLiquidity + } + 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: DepositMsgState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DepositMsgState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgHeight", wireType) + } + m.MsgHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MsgHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgIndex", wireType) + } + m.MsgIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MsgIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Executed", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Executed = bool(v != 0) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Succeeded", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Succeeded = bool(v != 0) + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ToBeDeleted", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ToBeDeleted = bool(v != 0) + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Msg == nil { + m.Msg = &MsgDepositWithinBatch{} + } + if err := m.Msg.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLiquidity(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLiquidity + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *WithdrawMsgState) 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 ErrIntOverflowLiquidity + } + 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: WithdrawMsgState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WithdrawMsgState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgHeight", wireType) + } + m.MsgHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MsgHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgIndex", wireType) + } + m.MsgIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MsgIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Executed", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Executed = bool(v != 0) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Succeeded", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Succeeded = bool(v != 0) + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ToBeDeleted", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ToBeDeleted = bool(v != 0) + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Msg == nil { + m.Msg = &MsgWithdrawWithinBatch{} + } + if err := m.Msg.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLiquidity(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLiquidity + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SwapMsgState) 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 ErrIntOverflowLiquidity + } + 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: SwapMsgState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SwapMsgState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgHeight", wireType) + } + m.MsgHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MsgHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgIndex", wireType) + } + m.MsgIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MsgIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Executed", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Executed = bool(v != 0) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Succeeded", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Succeeded = bool(v != 0) + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ToBeDeleted", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ToBeDeleted = bool(v != 0) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OrderExpiryHeight", wireType) + } + m.OrderExpiryHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OrderExpiryHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExchangedOfferCoin", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ExchangedOfferCoin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RemainingOfferCoin", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.RemainingOfferCoin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReservedOfferCoinFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ReservedOfferCoinFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLiquidity + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLiquidity + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLiquidity + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Msg == nil { + m.Msg = &MsgSwapWithinBatch{} + } + if err := m.Msg.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLiquidity(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLiquidity + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipLiquidity(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, ErrIntOverflowLiquidity + } + 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, ErrIntOverflowLiquidity + } + 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, ErrIntOverflowLiquidity + } + 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, ErrInvalidLengthLiquidity + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupLiquidity + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthLiquidity + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthLiquidity = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowLiquidity = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupLiquidity = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/liquidity/types/liquidity_pool.go b/x/liquidity/types/liquidity_pool.go new file mode 100644 index 00000000000..710a3b14a77 --- /dev/null +++ b/x/liquidity/types/liquidity_pool.go @@ -0,0 +1,190 @@ +package types + +import ( + "strconv" + "strings" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// PoolName returns unique name of the pool consists of given reserve coin denoms and type id. +func PoolName(reserveCoinDenoms []string, poolTypeID uint32) string { + return strings.Join(append(SortDenoms(reserveCoinDenoms), strconv.FormatUint(uint64(poolTypeID), 10)), "/") +} + +// Name returns the pool's name. +func (pool Pool) Name() string { + return PoolName(pool.ReserveCoinDenoms, pool.TypeId) +} + +// Validate validates Pool. +func (pool Pool) Validate() error { + if pool.Id == 0 { + return ErrPoolNotExists + } + if pool.TypeId == 0 { + return ErrPoolTypeNotExists + } + if pool.ReserveCoinDenoms == nil || len(pool.ReserveCoinDenoms) == 0 { + return ErrNumOfReserveCoinDenoms + } + if uint32(len(pool.ReserveCoinDenoms)) > MaxReserveCoinNum || uint32(len(pool.ReserveCoinDenoms)) < MinReserveCoinNum { + return ErrNumOfReserveCoinDenoms + } + sortedDenomA, sortedDenomB := AlphabeticalDenomPair(pool.ReserveCoinDenoms[0], pool.ReserveCoinDenoms[1]) + if sortedDenomA != pool.ReserveCoinDenoms[0] || sortedDenomB != pool.ReserveCoinDenoms[1] { + return ErrBadOrderingReserveCoinDenoms + } + if pool.ReserveAccountAddress == "" { + return ErrEmptyReserveAccountAddress + } + if pool.ReserveAccountAddress != GetPoolReserveAcc(pool.Name(), false).String() { + return ErrBadReserveAccountAddress + } + if pool.PoolCoinDenom == "" { + return ErrEmptyPoolCoinDenom + } + if pool.PoolCoinDenom != pool.Name() { + return ErrBadPoolCoinDenom + } + return nil +} + +// NewPoolBatch creates a new PoolBatch object. +func NewPoolBatch(poolID, batchIndex uint64) PoolBatch { + return PoolBatch{ + PoolId: poolID, + Index: batchIndex, + BeginHeight: 0, + DepositMsgIndex: 1, + WithdrawMsgIndex: 1, + SwapMsgIndex: 1, + Executed: false, + } +} + +// MustMarshalPool returns the Pool bytes. Panics if fails. +func MustMarshalPool(cdc codec.BinaryCodec, liquidityPool Pool) []byte { + return cdc.MustMarshal(&liquidityPool) +} + +// MustUnmarshalPool returns the Pool from bytes. Panics if fails. +func MustUnmarshalPool(cdc codec.BinaryCodec, value []byte) Pool { + liquidityPool, err := UnmarshalPool(cdc, value) + if err != nil { + panic(err) + } + return liquidityPool +} + +// UnmarshalPool returns the Pool from bytes. +func UnmarshalPool(cdc codec.BinaryCodec, value []byte) (liquidityPool Pool, err error) { + err = cdc.Unmarshal(value, &liquidityPool) + return liquidityPool, err +} + +// GetReserveAccount returns sdk.AccAddress of the pool's reserve account. +func (pool Pool) GetReserveAccount() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(pool.ReserveAccountAddress) + if err != nil { + panic(err) + } + return addr +} + +// GetPoolCoinDenom returns the pool coin's denom. +func (pool Pool) GetPoolCoinDenom() string { return pool.PoolCoinDenom } + +// GetId returns id of the pool. +func (pool Pool) GetId() uint64 { return pool.Id } //nolint:revive + +// Pools is a collection of pools. +type Pools []Pool + +func (pools Pools) String() (out string) { + for _, del := range pools { + out += del.String() + "\n" + } + return strings.TrimSpace(out) +} + +// MustMarshalPoolBatch returns the PoolBatch bytes. Panics if fails. +func MustMarshalPoolBatch(cdc codec.BinaryCodec, poolBatch PoolBatch) []byte { + return cdc.MustMarshal(&poolBatch) +} + +// UnmarshalPoolBatch returns the PoolBatch from bytes. +func UnmarshalPoolBatch(cdc codec.BinaryCodec, value []byte) (poolBatch PoolBatch, err error) { + err = cdc.Unmarshal(value, &poolBatch) + return poolBatch, err +} + +// MustUnmarshalPoolBatch returns the PoolBatch from bytes. Panics if fails. +func MustUnmarshalPoolBatch(cdc codec.BinaryCodec, value []byte) PoolBatch { + poolBatch, err := UnmarshalPoolBatch(cdc, value) + if err != nil { + panic(err) + } + return poolBatch +} + +// MustMarshalDepositMsgState returns the DepositMsgState bytes. Panics if fails. +func MustMarshalDepositMsgState(cdc codec.BinaryCodec, msg DepositMsgState) []byte { + return cdc.MustMarshal(&msg) +} + +// UnmarshalDepositMsgState returns the DepositMsgState from bytes. +func UnmarshalDepositMsgState(cdc codec.BinaryCodec, value []byte) (msg DepositMsgState, err error) { + err = cdc.Unmarshal(value, &msg) + return msg, err +} + +// MustUnmarshalDepositMsgState returns the DepositMsgState from bytes. Panics if fails. +func MustUnmarshalDepositMsgState(cdc codec.BinaryCodec, value []byte) DepositMsgState { + msg, err := UnmarshalDepositMsgState(cdc, value) + if err != nil { + panic(err) + } + return msg +} + +// MustMarshalWithdrawMsgState returns the WithdrawMsgState bytes. Panics if fails. +func MustMarshalWithdrawMsgState(cdc codec.BinaryCodec, msg WithdrawMsgState) []byte { + return cdc.MustMarshal(&msg) +} + +// UnmarshalWithdrawMsgState returns the WithdrawMsgState from bytes. +func UnmarshalWithdrawMsgState(cdc codec.BinaryCodec, value []byte) (msg WithdrawMsgState, err error) { + err = cdc.Unmarshal(value, &msg) + return msg, err +} + +// MustUnmarshalWithdrawMsgState returns the WithdrawMsgState from bytes. Panics if fails. +func MustUnmarshalWithdrawMsgState(cdc codec.BinaryCodec, value []byte) WithdrawMsgState { + msg, err := UnmarshalWithdrawMsgState(cdc, value) + if err != nil { + panic(err) + } + return msg +} + +// MustMarshalSwapMsgState returns the SwapMsgState bytes. Panics if fails. +func MustMarshalSwapMsgState(cdc codec.BinaryCodec, msg SwapMsgState) []byte { + return cdc.MustMarshal(&msg) +} + +// UnmarshalSwapMsgState returns the UnmarshalSwapMsgState from bytes. +func UnmarshalSwapMsgState(cdc codec.BinaryCodec, value []byte) (msg SwapMsgState, err error) { + err = cdc.Unmarshal(value, &msg) + return msg, err +} + +// MustUnmarshalSwapMsgState returns the SwapMsgState from bytes. Panics if fails. +func MustUnmarshalSwapMsgState(cdc codec.BinaryCodec, value []byte) SwapMsgState { + msg, err := UnmarshalSwapMsgState(cdc, value) + if err != nil { + panic(err) + } + return msg +} diff --git a/x/liquidity/types/liquidity_pool_test.go b/x/liquidity/types/liquidity_pool_test.go new file mode 100644 index 00000000000..1f23a569fd6 --- /dev/null +++ b/x/liquidity/types/liquidity_pool_test.go @@ -0,0 +1,133 @@ +package types_test + +import ( + "strings" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestUnmarshalerPanics(t *testing.T) { + t.Run("MustUnmarshalPool", func(t *testing.T) { + require.Panics(t, func() { + types.MustUnmarshalPool(types.ModuleCdc, []byte{0x00}) + }) + }) + t.Run("MustUnmarshalPoolBatch", func(t *testing.T) { + require.Panics(t, func() { + types.MustUnmarshalPoolBatch(types.ModuleCdc, []byte{0x00}) + }) + }) + t.Run("MustUnmarshalDepositMsgState", func(t *testing.T) { + require.Panics(t, func() { + types.MustUnmarshalDepositMsgState(types.ModuleCdc, []byte{0x00}) + }) + }) + t.Run("MustUnmarshalWithdrawMsgState", func(t *testing.T) { + require.Panics(t, func() { + types.MustUnmarshalWithdrawMsgState(types.ModuleCdc, []byte{0x00}) + }) + }) + t.Run("MustUnmarshalSwapMsgState", func(t *testing.T) { + require.Panics(t, func() { + types.MustUnmarshalSwapMsgState(types.ModuleCdc, []byte{0x00}) + }) + }) +} + +func TestLiquidityPoolBatch(t *testing.T) { + simapp, ctx := app.CreateTestInput() + params := simapp.LiquidityKeeper.GetParams(ctx) + + pool := types.Pool{} + require.Equal(t, types.ErrPoolNotExists, pool.Validate()) + + pool.Id = 1 + require.Equal(t, types.ErrPoolTypeNotExists, pool.Validate()) + + pool.TypeId = 1 + require.Equal(t, types.ErrNumOfReserveCoinDenoms, pool.Validate()) + + pool.ReserveCoinDenoms = []string{DenomY, DenomX, DenomX} + require.Equal(t, types.ErrNumOfReserveCoinDenoms, pool.Validate()) + + pool.ReserveCoinDenoms = []string{DenomY, DenomX} + require.Equal(t, types.ErrBadOrderingReserveCoinDenoms, pool.Validate()) + + pool.ReserveCoinDenoms = []string{DenomX, DenomY} + require.Equal(t, types.ErrEmptyReserveAccountAddress, pool.Validate()) + + pool.ReserveAccountAddress = "badaddress" + require.Equal(t, types.ErrBadReserveAccountAddress, pool.Validate()) + + pool.ReserveAccountAddress = types.GetPoolReserveAcc(pool.Name(), false).String() + add2, err := sdk.AccAddressFromBech32(pool.ReserveAccountAddress) + require.NoError(t, err) + require.Equal(t, add2, pool.GetReserveAccount()) + require.Equal(t, types.ErrEmptyPoolCoinDenom, pool.Validate()) + + pool.PoolCoinDenom = "badPoolCoinDenom" + require.Equal(t, types.ErrBadPoolCoinDenom, pool.Validate()) + + pool.PoolCoinDenom = pool.Name() + require.NoError(t, pool.Validate()) + require.Equal(t, pool.Name(), types.PoolName(pool.ReserveCoinDenoms, pool.TypeId)) + require.Equal(t, pool.Id, pool.GetId()) + require.Equal(t, pool.PoolCoinDenom, pool.GetPoolCoinDenom()) + + cdc := simapp.AppCodec() + poolByte := types.MustMarshalPool(cdc, pool) + require.Equal(t, pool, types.MustUnmarshalPool(cdc, poolByte)) + + poolByte = types.MustMarshalPool(cdc, pool) + poolMarshaled, err := types.UnmarshalPool(cdc, poolByte) + require.NoError(t, err) + require.Equal(t, pool, poolMarshaled) + + addr, err := sdk.AccAddressFromBech32(pool.ReserveAccountAddress) + require.NoError(t, err) + require.True(t, pool.GetReserveAccount().Equals(addr)) + require.Equal(t, strings.TrimSpace(pool.String()+"\n"+pool.String()), types.Pools{pool, pool}.String()) + + simapp.LiquidityKeeper.SetPool(ctx, pool) + batch := types.NewPoolBatch(pool.Id, 1) + simapp.LiquidityKeeper.SetPoolBatch(ctx, batch) + batchByte := types.MustMarshalPoolBatch(cdc, batch) + require.Equal(t, batch, types.MustUnmarshalPoolBatch(cdc, batchByte)) + + batchMarshaled, err := types.UnmarshalPoolBatch(cdc, batchByte) + require.NoError(t, err) + require.Equal(t, batch, batchMarshaled) + + batchDepositMsg := types.DepositMsgState{} + batchWithdrawMsg := types.WithdrawMsgState{} + batchSwapMsg := types.SwapMsgState{ + ExchangedOfferCoin: sdk.NewCoin("test", sdk.NewInt(1000)), + RemainingOfferCoin: sdk.NewCoin("test", sdk.NewInt(1000)), + ReservedOfferCoinFee: types.GetOfferCoinFee(sdk.NewCoin("test", sdk.NewInt(2000)), params.SwapFeeRate), + } + b := types.MustMarshalDepositMsgState(cdc, batchDepositMsg) + require.Equal(t, batchDepositMsg, types.MustUnmarshalDepositMsgState(cdc, b)) + + marshaled, err := types.UnmarshalDepositMsgState(cdc, b) + require.NoError(t, err) + require.Equal(t, batchDepositMsg, marshaled) + + b = types.MustMarshalWithdrawMsgState(cdc, batchWithdrawMsg) + require.Equal(t, batchWithdrawMsg, types.MustUnmarshalWithdrawMsgState(cdc, b)) + + withdrawMsgMarshaled, err := types.UnmarshalWithdrawMsgState(cdc, b) + require.NoError(t, err) + require.Equal(t, batchWithdrawMsg, withdrawMsgMarshaled) + + b = types.MustMarshalSwapMsgState(cdc, batchSwapMsg) + require.Equal(t, batchSwapMsg, types.MustUnmarshalSwapMsgState(cdc, b)) + + SwapMsgMarshaled, err := types.UnmarshalSwapMsgState(cdc, b) + require.NoError(t, err) + require.Equal(t, batchSwapMsg, SwapMsgMarshaled) +} diff --git a/x/liquidity/types/msgs.go b/x/liquidity/types/msgs.go new file mode 100644 index 00000000000..a77b482dec8 --- /dev/null +++ b/x/liquidity/types/msgs.go @@ -0,0 +1,230 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + _ sdk.Msg = (*MsgCreatePool)(nil) + _ sdk.Msg = (*MsgDepositWithinBatch)(nil) + _ sdk.Msg = (*MsgWithdrawWithinBatch)(nil) + _ sdk.Msg = (*MsgSwapWithinBatch)(nil) +) + +// Message types for the liquidity module +// +//nolint:gosec +const ( + TypeMsgCreatePool = "create_pool" + TypeMsgDepositWithinBatch = "deposit_within_batch" + TypeMsgWithdrawWithinBatch = "withdraw_within_batch" + TypeMsgSwapWithinBatch = "swap_within_batch" +) + +// NewMsgCreatePool creates a new MsgCreatePool. +func NewMsgCreatePool(poolCreator sdk.AccAddress, poolTypeID uint32, depositCoins sdk.Coins) *MsgCreatePool { + return &MsgCreatePool{ + PoolCreatorAddress: poolCreator.String(), + PoolTypeId: poolTypeID, + DepositCoins: depositCoins, + } +} + +func (msg MsgCreatePool) Route() string { return RouterKey } + +func (msg MsgCreatePool) Type() string { return TypeMsgCreatePool } + +func (msg MsgCreatePool) ValidateBasic() error { + if 1 > msg.PoolTypeId { + return ErrBadPoolTypeID + } + if _, err := sdk.AccAddressFromBech32(msg.PoolCreatorAddress); err != nil { + return ErrInvalidPoolCreatorAddr + } + if err := msg.DepositCoins.Validate(); err != nil { + return err + } + if n := uint32(len(msg.DepositCoins)); n > MaxReserveCoinNum || n < MinReserveCoinNum { + return ErrNumOfReserveCoin + } + return nil +} + +func (msg MsgCreatePool) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} + +func (msg MsgCreatePool) GetSigners() []sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(msg.PoolCreatorAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{addr} +} + +func (msg MsgCreatePool) GetPoolCreator() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(msg.PoolCreatorAddress) + if err != nil { + panic(err) + } + return addr +} + +// NewMsgDepositWithinBatch creates a new MsgDepositWithinBatch. +func NewMsgDepositWithinBatch(depositor sdk.AccAddress, poolID uint64, depositCoins sdk.Coins) *MsgDepositWithinBatch { + return &MsgDepositWithinBatch{ + DepositorAddress: depositor.String(), + PoolId: poolID, + DepositCoins: depositCoins, + } +} + +func (msg MsgDepositWithinBatch) Route() string { return RouterKey } + +func (msg MsgDepositWithinBatch) Type() string { return TypeMsgDepositWithinBatch } + +func (msg MsgDepositWithinBatch) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.DepositorAddress); err != nil { + return ErrInvalidDepositorAddr + } + if err := msg.DepositCoins.Validate(); err != nil { + return err + } + if !msg.DepositCoins.IsAllPositive() { + return ErrBadDepositCoinsAmount + } + if n := uint32(len(msg.DepositCoins)); n > MaxReserveCoinNum || n < MinReserveCoinNum { + return ErrNumOfReserveCoin + } + return nil +} + +func (msg MsgDepositWithinBatch) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} + +func (msg MsgDepositWithinBatch) GetSigners() []sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(msg.DepositorAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{addr} +} + +func (msg MsgDepositWithinBatch) GetDepositor() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(msg.DepositorAddress) + if err != nil { + panic(err) + } + return addr +} + +// NewMsgWithdrawWithinBatch creates a new MsgWithdrawWithinBatch. +func NewMsgWithdrawWithinBatch(withdrawer sdk.AccAddress, poolID uint64, poolCoin sdk.Coin) *MsgWithdrawWithinBatch { + return &MsgWithdrawWithinBatch{ + WithdrawerAddress: withdrawer.String(), + PoolId: poolID, + PoolCoin: poolCoin, + } +} + +func (msg MsgWithdrawWithinBatch) Route() string { return RouterKey } + +func (msg MsgWithdrawWithinBatch) Type() string { return TypeMsgWithdrawWithinBatch } + +func (msg MsgWithdrawWithinBatch) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.WithdrawerAddress); err != nil { + return ErrInvalidWithdrawerAddr + } + if err := msg.PoolCoin.Validate(); err != nil { + return err + } + if !msg.PoolCoin.IsPositive() { + return ErrBadPoolCoinAmount + } + return nil +} + +func (msg MsgWithdrawWithinBatch) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} + +func (msg MsgWithdrawWithinBatch) GetSigners() []sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(msg.WithdrawerAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{addr} +} + +func (msg MsgWithdrawWithinBatch) GetWithdrawer() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(msg.WithdrawerAddress) + if err != nil { + panic(err) + } + return addr +} + +// NewMsgSwapWithinBatch creates a new MsgSwapWithinBatch. +func NewMsgSwapWithinBatch( + swapRequester sdk.AccAddress, + poolID uint64, + swapTypeID uint32, + offerCoin sdk.Coin, + demandCoinDenom string, + orderPrice sdk.Dec, + swapFeeRate sdk.Dec, +) *MsgSwapWithinBatch { + return &MsgSwapWithinBatch{ + SwapRequesterAddress: swapRequester.String(), + PoolId: poolID, + SwapTypeId: swapTypeID, + OfferCoin: offerCoin, + OfferCoinFee: GetOfferCoinFee(offerCoin, swapFeeRate), + DemandCoinDenom: demandCoinDenom, + OrderPrice: orderPrice, + } +} + +func (msg MsgSwapWithinBatch) Route() string { return RouterKey } + +func (msg MsgSwapWithinBatch) Type() string { return TypeMsgSwapWithinBatch } + +func (msg MsgSwapWithinBatch) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.SwapRequesterAddress); err != nil { + return ErrInvalidSwapRequesterAddr + } + if err := msg.OfferCoin.Validate(); err != nil { + return err + } + if !msg.OfferCoin.IsPositive() { + return ErrBadOfferCoinAmount + } + if !msg.OrderPrice.IsPositive() { + return ErrBadOrderPrice + } + if !msg.OfferCoin.Amount.GTE(MinOfferCoinAmount) { + return ErrLessThanMinOfferAmount + } + return nil +} + +func (msg MsgSwapWithinBatch) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} + +func (msg MsgSwapWithinBatch) GetSigners() []sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(msg.SwapRequesterAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{addr} +} + +func (msg MsgSwapWithinBatch) GetSwapRequester() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(msg.SwapRequesterAddress) + if err != nil { + panic(err) + } + return addr +} diff --git a/x/liquidity/types/msgs_test.go b/x/liquidity/types/msgs_test.go new file mode 100644 index 00000000000..67d6e660cfe --- /dev/null +++ b/x/liquidity/types/msgs_test.go @@ -0,0 +1,406 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +const ( + DefaultPoolTypeId = uint32(1) + DefaultPoolId = uint64(1) + DefaultSwapTypeId = uint32(1) + DenomX = "denomX" + DenomY = "denomY" +) + +func TestMsgCreatePool(t *testing.T) { + poolCreator := sdk.AccAddress(crypto.AddressHash([]byte("testAccount"))) + + cases := []struct { + expectedErr string // empty means no error expected + msg *types.MsgCreatePool + }{ + { + "", + types.NewMsgCreatePool(poolCreator, DefaultPoolTypeId, sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(1000)), sdk.NewCoin(DenomY, sdk.NewInt(1000)))), + }, + { + "invalid index of the pool type", + types.NewMsgCreatePool(poolCreator, 0, sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(1000)), sdk.NewCoin(DenomY, sdk.NewInt(1000)))), + }, + { + "invalid pool creator address", + types.NewMsgCreatePool(sdk.AccAddress{}, DefaultPoolTypeId, sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(1000)), sdk.NewCoin(DenomY, sdk.NewInt(1000)))), + }, + { + "invalid number of reserve coin", + types.NewMsgCreatePool(poolCreator, DefaultPoolTypeId, sdk.NewCoins(sdk.NewCoin(DenomY, sdk.NewInt(1000)))), + }, + { + "invalid number of reserve coin", + types.NewMsgCreatePool(poolCreator, DefaultPoolTypeId, sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(1000)), sdk.NewCoin(DenomY, sdk.NewInt(1000)), sdk.NewCoin("denomZ", sdk.NewInt(1000)))), + }, + } + + for _, tc := range cases { + require.IsType(t, &types.MsgCreatePool{}, tc.msg) + require.Equal(t, types.TypeMsgCreatePool, tc.msg.Type()) + require.Equal(t, types.RouterKey, tc.msg.Route()) + require.Equal(t, sdk.MustSortJSON(types.ModuleCdc.MustMarshalJSON(tc.msg)), tc.msg.GetSignBytes()) + + err := tc.msg.ValidateBasic() + if tc.expectedErr == "" { + require.Nil(t, err) + signers := tc.msg.GetSigners() + require.Len(t, signers, 1) + require.Equal(t, tc.msg.GetPoolCreator(), signers[0]) + } else { + require.EqualError(t, err, tc.expectedErr) + } + } +} + +func TestMsgDepositWithinBatch(t *testing.T) { + depositor := sdk.AccAddress(crypto.AddressHash([]byte("testAccount"))) + + cases := []struct { + expectedErr string // empty means no error expected + msg *types.MsgDepositWithinBatch + }{ + { + "", + types.NewMsgDepositWithinBatch(depositor, DefaultPoolId, sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(1000)), sdk.NewCoin(DenomY, sdk.NewInt(1000)))), + }, + { + "", + types.NewMsgDepositWithinBatch(depositor, 0, sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(1000)), sdk.NewCoin(DenomY, sdk.NewInt(1000)))), + }, + { + "invalid pool depositor address", + types.NewMsgDepositWithinBatch(sdk.AccAddress{}, DefaultPoolId, sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(1000)), sdk.NewCoin(DenomY, sdk.NewInt(1000)))), + }, + { + "invalid number of reserve coin", + types.NewMsgDepositWithinBatch(depositor, DefaultPoolId, sdk.NewCoins(sdk.NewCoin(DenomY, sdk.NewInt(1000)))), + }, + } + + for _, tc := range cases { + require.IsType(t, &types.MsgDepositWithinBatch{}, tc.msg) + require.Equal(t, types.TypeMsgDepositWithinBatch, tc.msg.Type()) + require.Equal(t, types.RouterKey, tc.msg.Route()) + require.Equal(t, sdk.MustSortJSON(types.ModuleCdc.MustMarshalJSON(tc.msg)), tc.msg.GetSignBytes()) + + err := tc.msg.ValidateBasic() + if tc.expectedErr == "" { + require.Nil(t, err) + signers := tc.msg.GetSigners() + require.Len(t, signers, 1) + require.Equal(t, tc.msg.GetDepositor(), signers[0]) + } else { + require.EqualError(t, err, tc.expectedErr) + } + } +} + +func TestMsgWithdrawWithinBatch(t *testing.T) { + withdrawer := sdk.AccAddress(crypto.AddressHash([]byte("testAccount"))) + poolCoinDenom := "poolCoinDenom" + + cases := []struct { + expectedErr string // empty means no error expected + msg *types.MsgWithdrawWithinBatch + }{ + { + "", + types.NewMsgWithdrawWithinBatch(withdrawer, DefaultPoolId, sdk.NewCoin(poolCoinDenom, sdk.NewInt(1000))), + }, + { + "invalid pool withdrawer address", + types.NewMsgWithdrawWithinBatch(sdk.AccAddress{}, DefaultPoolId, sdk.NewCoin(poolCoinDenom, sdk.NewInt(1000))), + }, + { + "invalid pool coin amount", + types.NewMsgWithdrawWithinBatch(withdrawer, DefaultPoolId, sdk.NewCoin(poolCoinDenom, sdk.NewInt(0))), + }, + } + + for _, tc := range cases { + require.IsType(t, &types.MsgWithdrawWithinBatch{}, tc.msg) + require.Equal(t, types.TypeMsgWithdrawWithinBatch, tc.msg.Type()) + require.Equal(t, types.RouterKey, tc.msg.Route()) + require.Equal(t, sdk.MustSortJSON(types.ModuleCdc.MustMarshalJSON(tc.msg)), tc.msg.GetSignBytes()) + + err := tc.msg.ValidateBasic() + if tc.expectedErr == "" { + require.Nil(t, err) + signers := tc.msg.GetSigners() + require.Len(t, signers, 1) + require.Equal(t, tc.msg.GetWithdrawer(), signers[0]) + } else { + require.EqualError(t, err, tc.expectedErr) + } + } +} + +func TestMsgSwapWithinBatch(t *testing.T) { + swapRequester := sdk.AccAddress(crypto.AddressHash([]byte("testAccount"))) + offerCoin := sdk.NewCoin(DenomX, sdk.NewInt(1000)) + orderPrice, err := sdk.NewDecFromStr("0.1") + require.NoError(t, err) + + cases := []struct { + expectedErr string // empty means no error expected + msg *types.MsgSwapWithinBatch + }{ + { + "", + types.NewMsgSwapWithinBatch(swapRequester, DefaultPoolId, DefaultSwapTypeId, offerCoin, DenomY, orderPrice, types.DefaultSwapFeeRate), + }, + { + "invalid pool swap requester address", + types.NewMsgSwapWithinBatch(sdk.AccAddress{}, DefaultPoolId, DefaultSwapTypeId, offerCoin, DenomY, orderPrice, types.DefaultSwapFeeRate), + }, + { + "invalid offer coin amount", + types.NewMsgSwapWithinBatch(swapRequester, DefaultPoolId, DefaultSwapTypeId, sdk.NewCoin(DenomX, sdk.NewInt(0)), DenomY, orderPrice, types.DefaultSwapFeeRate), + }, + { + "invalid order price", + types.NewMsgSwapWithinBatch(swapRequester, DefaultPoolId, DefaultSwapTypeId, offerCoin, DenomY, sdk.ZeroDec(), types.DefaultSwapFeeRate), + }, + { + "offer amount should be over 100 micro", + types.NewMsgSwapWithinBatch(swapRequester, DefaultPoolId, DefaultSwapTypeId, sdk.NewCoin(DenomX, sdk.NewInt(1)), DenomY, orderPrice, types.DefaultSwapFeeRate), + }, + } + + for _, tc := range cases { + require.IsType(t, &types.MsgSwapWithinBatch{}, tc.msg) + require.Equal(t, types.TypeMsgSwapWithinBatch, tc.msg.Type()) + require.Equal(t, types.RouterKey, tc.msg.Route()) + require.Equal(t, sdk.MustSortJSON(types.ModuleCdc.MustMarshalJSON(tc.msg)), tc.msg.GetSignBytes()) + + err := tc.msg.ValidateBasic() + if tc.expectedErr == "" { + require.Nil(t, err) + signers := tc.msg.GetSigners() + require.Len(t, signers, 1) + require.Equal(t, tc.msg.GetSwapRequester(), signers[0]) + } else { + require.EqualError(t, err, tc.expectedErr) + } + } +} + +func TestMsgPanics(t *testing.T) { + emptyMsgCreatePool := types.MsgCreatePool{} + emptyMsgDeposit := types.MsgDepositWithinBatch{} + emptyMsgWithdraw := types.MsgWithdrawWithinBatch{} + emptyMsgSwap := types.MsgSwapWithinBatch{} + for _, msg := range []sdk.Msg{&emptyMsgCreatePool, &emptyMsgDeposit, &emptyMsgWithdraw, &emptyMsgSwap} { + require.PanicsWithError(t, "empty address string is not allowed", func() { msg.GetSigners() }) + } + for _, tc := range []func() sdk.AccAddress{ + emptyMsgCreatePool.GetPoolCreator, + emptyMsgDeposit.GetDepositor, + emptyMsgWithdraw.GetWithdrawer, + emptyMsgSwap.GetSwapRequester, + } { + require.PanicsWithError(t, "empty address string is not allowed", func() { tc() }) + } +} + +func TestMsgValidateBasic(t *testing.T) { + validPoolTypeId := DefaultPoolTypeId + validAddr := sdk.AccAddress(crypto.AddressHash([]byte("testAccount"))).String() + validCoin := sdk.NewCoin(DenomY, sdk.NewInt(10000)) + + invalidDenomCoin := sdk.Coin{Denom: "-", Amount: sdk.NewInt(10000)} + negativeCoin := sdk.Coin{Denom: DenomX, Amount: sdk.NewInt(-1)} + zeroCoin := sdk.Coin{Denom: DenomX, Amount: sdk.ZeroInt()} + + coinsWithInvalidDenom := sdk.Coins{invalidDenomCoin, validCoin} + coinsWithNegative := sdk.Coins{negativeCoin, validCoin} + coinsWithZero := sdk.Coins{zeroCoin, validCoin} + + invalidDenomErrMsg := "invalid denom: -" + negativeCoinErrMsg := "coin -1denomX amount is not positive" + negativeAmountErrMsg := "negative coin amount: -1" + zeroCoinErrMsg := "coin 0denomX amount is not positive" + + t.Run("MsgCreatePool", func(t *testing.T) { + for _, tc := range []struct { + msg types.MsgCreatePool + errMsg string + }{ + { + types.MsgCreatePool{}, + types.ErrBadPoolTypeID.Error(), + }, + { + types.MsgCreatePool{PoolTypeId: validPoolTypeId}, + types.ErrInvalidPoolCreatorAddr.Error(), + }, + { + types.MsgCreatePool{PoolCreatorAddress: validAddr, PoolTypeId: validPoolTypeId}, + types.ErrNumOfReserveCoin.Error(), + }, + { + types.MsgCreatePool{ + PoolCreatorAddress: validAddr, + PoolTypeId: validPoolTypeId, + DepositCoins: coinsWithInvalidDenom, + }, + invalidDenomErrMsg, + }, + { + types.MsgCreatePool{ + PoolCreatorAddress: validAddr, + PoolTypeId: validPoolTypeId, + DepositCoins: coinsWithNegative, + }, + negativeCoinErrMsg, + }, + { + types.MsgCreatePool{ + PoolCreatorAddress: validAddr, + PoolTypeId: validPoolTypeId, + DepositCoins: coinsWithZero, + }, + zeroCoinErrMsg, + }, + { + types.MsgCreatePool{ + PoolCreatorAddress: validAddr, + PoolTypeId: validPoolTypeId, + DepositCoins: sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(int64(types.MinReserveCoinNum)-1))), + }, + types.ErrNumOfReserveCoin.Error(), + }, + { + types.MsgCreatePool{ + PoolCreatorAddress: validAddr, + PoolTypeId: validPoolTypeId, + DepositCoins: sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(int64(types.MaxReserveCoinNum)+1))), + }, + types.ErrNumOfReserveCoin.Error(), + }, + } { + err := tc.msg.ValidateBasic() + require.EqualError(t, err, tc.errMsg) + } + }) + t.Run("MsgDepositWithinBatch", func(t *testing.T) { + for _, tc := range []struct { + msg types.MsgDepositWithinBatch + errMsg string + }{ + { + types.MsgDepositWithinBatch{}, + types.ErrInvalidDepositorAddr.Error(), + }, + { + types.MsgDepositWithinBatch{DepositorAddress: validAddr}, + types.ErrBadDepositCoinsAmount.Error(), + }, + { + types.MsgDepositWithinBatch{DepositorAddress: validAddr, DepositCoins: coinsWithInvalidDenom}, + invalidDenomErrMsg, + }, + { + types.MsgDepositWithinBatch{DepositorAddress: validAddr, DepositCoins: coinsWithNegative}, + negativeCoinErrMsg, + }, + { + types.MsgDepositWithinBatch{DepositorAddress: validAddr, DepositCoins: coinsWithZero}, + zeroCoinErrMsg, + }, + { + types.MsgDepositWithinBatch{ + DepositorAddress: validAddr, + DepositCoins: sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(int64(types.MinReserveCoinNum)-1))), + }, + types.ErrNumOfReserveCoin.Error(), + }, + { + types.MsgDepositWithinBatch{ + DepositorAddress: validAddr, + DepositCoins: sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(int64(types.MaxReserveCoinNum)+1))), + }, + types.ErrNumOfReserveCoin.Error(), + }, + } { + err := tc.msg.ValidateBasic() + require.EqualError(t, err, tc.errMsg) + } + }) + t.Run("MsgWithdrawWithinBatch", func(t *testing.T) { + for _, tc := range []struct { + msg types.MsgWithdrawWithinBatch + errMsg string + }{ + { + types.MsgWithdrawWithinBatch{}, + types.ErrInvalidWithdrawerAddr.Error(), + }, + { + types.MsgWithdrawWithinBatch{WithdrawerAddress: validAddr, PoolCoin: invalidDenomCoin}, + invalidDenomErrMsg, + }, + { + types.MsgWithdrawWithinBatch{WithdrawerAddress: validAddr, PoolCoin: negativeCoin}, + negativeAmountErrMsg, + }, + { + types.MsgWithdrawWithinBatch{WithdrawerAddress: validAddr, PoolCoin: zeroCoin}, + types.ErrBadPoolCoinAmount.Error(), + }, + } { + err := tc.msg.ValidateBasic() + require.EqualError(t, err, tc.errMsg) + } + }) + t.Run("MsgSwap", func(t *testing.T) { + offerCoin := sdk.NewCoin(DenomX, sdk.NewInt(10000)) + orderPrice := sdk.MustNewDecFromStr("1.0") + + for _, tc := range []struct { + msg types.MsgSwapWithinBatch + errMsg string + }{ + { + types.MsgSwapWithinBatch{}, + types.ErrInvalidSwapRequesterAddr.Error(), + }, + { + types.MsgSwapWithinBatch{SwapRequesterAddress: validAddr, OfferCoin: invalidDenomCoin, OrderPrice: orderPrice}, + invalidDenomErrMsg, + }, + { + types.MsgSwapWithinBatch{SwapRequesterAddress: validAddr, OfferCoin: zeroCoin}, + types.ErrBadOfferCoinAmount.Error(), + }, + { + types.MsgSwapWithinBatch{SwapRequesterAddress: validAddr, OfferCoin: negativeCoin}, + negativeAmountErrMsg, + }, + { + types.MsgSwapWithinBatch{SwapRequesterAddress: validAddr, OfferCoin: offerCoin, OrderPrice: sdk.ZeroDec()}, + types.ErrBadOrderPrice.Error(), + }, + { + types.MsgSwapWithinBatch{SwapRequesterAddress: validAddr, OfferCoin: sdk.NewCoin(DenomX, sdk.OneInt()), OrderPrice: orderPrice}, + types.ErrLessThanMinOfferAmount.Error(), + }, + } { + err := tc.msg.ValidateBasic() + require.EqualError(t, err, tc.errMsg) + } + }) +} diff --git a/x/liquidity/types/params.go b/x/liquidity/types/params.go new file mode 100644 index 00000000000..d40d195fb46 --- /dev/null +++ b/x/liquidity/types/params.go @@ -0,0 +1,318 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + "gopkg.in/yaml.v2" +) + +const ( + // CancelOrderLifeSpan is the lifespan of order cancellation. + CancelOrderLifeSpan int64 = 0 + + // MinReserveCoinNum is the minimum number of reserve coins in each liquidity pool. + MinReserveCoinNum uint32 = 2 + + // MaxReserveCoinNum is the maximum number of reserve coins in each liquidity pool. + MaxReserveCoinNum uint32 = 2 + + // DefaultUnitBatchHeight is the default number of blocks in one batch. This param is used for scalability. + DefaultUnitBatchHeight uint32 = 1 + + // DefaultPoolTypeID is the default pool type id. The only supported pool type id is 1. + DefaultPoolTypeID uint32 = 1 + + // DefaultSwapTypeID is the default swap type id. The only supported swap type (instant swap) id is 1. + DefaultSwapTypeID uint32 = 1 + + // DefaultCircuitBreakerEnabled is the default circuit breaker status. This param is used for a contingency plan. + DefaultCircuitBreakerEnabled = false +) + +// Parameter store keys +var ( + KeyPoolTypes = []byte("PoolTypes") + KeyMinInitDepositAmount = []byte("MinInitDepositAmount") + KeyInitPoolCoinMintAmount = []byte("InitPoolCoinMintAmount") + KeyMaxReserveCoinAmount = []byte("MaxReserveCoinAmount") + KeySwapFeeRate = []byte("SwapFeeRate") + KeyPoolCreationFee = []byte("PoolCreationFee") + KeyUnitBatchHeight = []byte("UnitBatchHeight") + KeyWithdrawFeeRate = []byte("WithdrawFeeRate") + KeyMaxOrderAmountRatio = []byte("MaxOrderAmountRatio") + KeyCircuitBreakerEnabled = []byte("CircuitBreakerEnabled") +) + +var ( + DefaultMinInitDepositAmount = sdk.NewInt(1000000) + DefaultInitPoolCoinMintAmount = sdk.NewInt(1000000) + DefaultMaxReserveCoinAmount = sdk.ZeroInt() + DefaultSwapFeeRate = sdk.NewDecWithPrec(3, 3) // "0.003000000000000000" + DefaultWithdrawFeeRate = sdk.ZeroDec() + DefaultMaxOrderAmountRatio = sdk.NewDecWithPrec(1, 1) // "0.100000000000000000" + DefaultPoolCreationFee = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(40000000))) + DefaultPoolType = PoolType{ + Id: 1, + Name: "StandardLiquidityPool", + MinReserveCoinNum: MinReserveCoinNum, + MaxReserveCoinNum: MaxReserveCoinNum, + Description: "Standard liquidity pool with pool price function X/Y, ESPM constraint, and two kinds of reserve coins", + } + DefaultPoolTypes = []PoolType{DefaultPoolType} + + MinOfferCoinAmount = sdk.NewInt(100) +) + +var _ paramstypes.ParamSet = (*Params)(nil) + +// ParamKeyTable returns the parameter key table. +func ParamKeyTable() paramstypes.KeyTable { + return paramstypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// DefaultParams returns the default liquidity module parameters. +func DefaultParams() Params { + return Params{ + PoolTypes: DefaultPoolTypes, + MinInitDepositAmount: DefaultMinInitDepositAmount, + InitPoolCoinMintAmount: DefaultInitPoolCoinMintAmount, + MaxReserveCoinAmount: DefaultMaxReserveCoinAmount, + PoolCreationFee: DefaultPoolCreationFee, + SwapFeeRate: DefaultSwapFeeRate, + WithdrawFeeRate: DefaultWithdrawFeeRate, + MaxOrderAmountRatio: DefaultMaxOrderAmountRatio, + UnitBatchHeight: DefaultUnitBatchHeight, + CircuitBreakerEnabled: DefaultCircuitBreakerEnabled, + } +} + +// ParamSetPairs implements paramstypes.ParamSet. +func (p *Params) ParamSetPairs() paramstypes.ParamSetPairs { + return paramstypes.ParamSetPairs{ + paramstypes.NewParamSetPair(KeyPoolTypes, &p.PoolTypes, validatePoolTypes), + paramstypes.NewParamSetPair(KeyMinInitDepositAmount, &p.MinInitDepositAmount, validateMinInitDepositAmount), + paramstypes.NewParamSetPair(KeyInitPoolCoinMintAmount, &p.InitPoolCoinMintAmount, validateInitPoolCoinMintAmount), + paramstypes.NewParamSetPair(KeyMaxReserveCoinAmount, &p.MaxReserveCoinAmount, validateMaxReserveCoinAmount), + paramstypes.NewParamSetPair(KeyPoolCreationFee, &p.PoolCreationFee, validatePoolCreationFee), + paramstypes.NewParamSetPair(KeySwapFeeRate, &p.SwapFeeRate, validateSwapFeeRate), + paramstypes.NewParamSetPair(KeyWithdrawFeeRate, &p.WithdrawFeeRate, validateWithdrawFeeRate), + paramstypes.NewParamSetPair(KeyMaxOrderAmountRatio, &p.MaxOrderAmountRatio, validateMaxOrderAmountRatio), + paramstypes.NewParamSetPair(KeyUnitBatchHeight, &p.UnitBatchHeight, validateUnitBatchHeight), + paramstypes.NewParamSetPair(KeyCircuitBreakerEnabled, &p.CircuitBreakerEnabled, validateCircuitBreakerEnabled), + } +} + +// String returns a human readable string representation of the parameters. +func (p Params) String() string { + out, _ := yaml.Marshal(p) + return string(out) +} + +// Validate validates parameters. +func (p Params) Validate() error { + for _, v := range []struct { + value interface{} + validator func(interface{}) error + }{ + {p.PoolTypes, validatePoolTypes}, + {p.MinInitDepositAmount, validateMinInitDepositAmount}, + {p.InitPoolCoinMintAmount, validateInitPoolCoinMintAmount}, + {p.MaxReserveCoinAmount, validateMaxReserveCoinAmount}, + {p.PoolCreationFee, validatePoolCreationFee}, + {p.SwapFeeRate, validateSwapFeeRate}, + {p.WithdrawFeeRate, validateWithdrawFeeRate}, + {p.MaxOrderAmountRatio, validateMaxOrderAmountRatio}, + {p.UnitBatchHeight, validateUnitBatchHeight}, + {p.CircuitBreakerEnabled, validateCircuitBreakerEnabled}, + } { + if err := v.validator(v.value); err != nil { + return err + } + } + return nil +} + +func validatePoolTypes(i interface{}) error { + v, ok := i.([]PoolType) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if len(v) == 0 { + return fmt.Errorf("pool types must not be empty") + } + + for i, p := range v { + if int(p.Id) != i+1 { + return fmt.Errorf("pool type ids must be sorted") + } + if p.MaxReserveCoinNum > MaxReserveCoinNum || MinReserveCoinNum > p.MinReserveCoinNum { + return fmt.Errorf("min, max reserve coin num value of pool types are out of bounds") + } + } + + if len(v) > 1 || !v[0].Equal(DefaultPoolType) { + return fmt.Errorf("the only supported pool type is 1") + } + + return nil +} + +func validateMinInitDepositAmount(i interface{}) error { + v, ok := i.(sdk.Int) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNil() { + return fmt.Errorf("minimum initial deposit amount must not be nil") + } + + if !v.IsPositive() { + return fmt.Errorf("minimum initial deposit amount must be positive: %s", v) + } + + return nil +} + +func validateInitPoolCoinMintAmount(i interface{}) error { + v, ok := i.(sdk.Int) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNil() { + return fmt.Errorf("initial pool coin mint amount must not be nil") + } + + if !v.IsPositive() { + return fmt.Errorf("initial pool coin mint amount must be positive: %s", v) + } + + if v.LT(DefaultInitPoolCoinMintAmount) { + return fmt.Errorf("initial pool coin mint amount must be greater than or equal to 1000000: %s", v) + } + + return nil +} + +func validateMaxReserveCoinAmount(i interface{}) error { + v, ok := i.(sdk.Int) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNil() { + return fmt.Errorf("max reserve coin amount must not be nil") + } + + if v.IsNegative() { + return fmt.Errorf("max reserve coin amount must not be negative: %s", v) + } + + return nil +} + +func validateSwapFeeRate(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNil() { + return fmt.Errorf("swap fee rate must not be nil") + } + + if v.IsNegative() { + return fmt.Errorf("swap fee rate must not be negative: %s", v) + } + + if v.GT(sdk.OneDec()) { + return fmt.Errorf("swap fee rate too large: %s", v) + } + + return nil +} + +func validateWithdrawFeeRate(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNil() { + return fmt.Errorf("withdraw fee rate must not be nil") + } + + if v.IsNegative() { + return fmt.Errorf("withdraw fee rate must not be negative: %s", v) + } + + if v.GT(sdk.OneDec()) { + return fmt.Errorf("withdraw fee rate too large: %s", v) + } + + return nil +} + +func validateMaxOrderAmountRatio(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNil() { + return fmt.Errorf("max order amount ratio must not be nil") + } + + if v.IsNegative() { + return fmt.Errorf("max order amount ratio must not be negative: %s", v) + } + + if v.GT(sdk.OneDec()) { + return fmt.Errorf("max order amount ratio too large: %s", v) + } + + return nil +} + +func validatePoolCreationFee(i interface{}) error { + v, ok := i.(sdk.Coins) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if err := v.Validate(); err != nil { + return err + } + + if v.Empty() { + return fmt.Errorf("pool creation fee must not be empty") + } + + return nil +} + +func validateUnitBatchHeight(i interface{}) error { + v, ok := i.(uint32) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v == 0 { + return fmt.Errorf("unit batch height must be positive: %d", v) + } + + return nil +} + +func validateCircuitBreakerEnabled(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} diff --git a/x/liquidity/types/params_internal_test.go b/x/liquidity/types/params_internal_test.go new file mode 100644 index 00000000000..0ead3c92a1b --- /dev/null +++ b/x/liquidity/types/params_internal_test.go @@ -0,0 +1,26 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestValidateAuxFunctions(t *testing.T) { + type badType struct{} + for _, v := range []func(interface{}) error{ + validatePoolTypes, + validateMinInitDepositAmount, + validateInitPoolCoinMintAmount, + validateMaxReserveCoinAmount, + validatePoolCreationFee, + validateSwapFeeRate, + validateWithdrawFeeRate, + validateMaxOrderAmountRatio, + validateUnitBatchHeight, + validateCircuitBreakerEnabled, + } { + err := v(badType{}) + require.EqualError(t, err, "invalid parameter type: types.badType") + } +} diff --git a/x/liquidity/types/params_test.go b/x/liquidity/types/params_test.go new file mode 100644 index 00000000000..747d3ee5701 --- /dev/null +++ b/x/liquidity/types/params_test.go @@ -0,0 +1,243 @@ +package types_test + +import ( + "reflect" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestParams(t *testing.T) { + require.IsType(t, paramstypes.KeyTable{}, types.ParamKeyTable()) + + simapp, ctx := app.CreateTestInput() + defaultParams := types.DefaultParams() + require.Equal(t, defaultParams, simapp.LiquidityKeeper.GetParams(ctx)) + + paramsStr := `pool_types: +- id: 1 + name: StandardLiquidityPool + min_reserve_coin_num: 2 + max_reserve_coin_num: 2 + description: Standard liquidity pool with pool price function X/Y, ESPM constraint, + and two kinds of reserve coins +min_init_deposit_amount: "1000000" +init_pool_coin_mint_amount: "1000000" +max_reserve_coin_amount: "0" +pool_creation_fee: +- denom: stake + amount: "40000000" +swap_fee_rate: "0.003000000000000000" +withdraw_fee_rate: "0.000000000000000000" +max_order_amount_ratio: "0.100000000000000000" +unit_batch_height: 1 +circuit_breaker_enabled: false +` + require.Equal(t, paramsStr, defaultParams.String()) +} + +func TestParams_Validate(t *testing.T) { + require.NoError(t, types.DefaultParams().Validate()) + + testCases := []struct { + name string + configure func(*types.Params) + errString string + }{ + { + "EmptyPoolTypes", + func(params *types.Params) { + params.PoolTypes = []types.PoolType{} + }, + "pool types must not be empty", + }, + { + "TooManyPoolTypes", + func(params *types.Params) { + params.PoolTypes = []types.PoolType{types.DefaultPoolType, types.DefaultPoolType} + }, + "pool type ids must be sorted", + }, + { + "CustomPoolType", + func(params *types.Params) { + poolType := types.DefaultPoolType + poolType.Name = "CustomPoolType" + params.PoolTypes = []types.PoolType{poolType} + }, + "the only supported pool type is 1", + }, + { + "NilMinInitDepositAmount", + func(params *types.Params) { + params.MinInitDepositAmount = sdk.Int{} + }, + "minimum initial deposit amount must not be nil", + }, + { + "NonPositiveMinInitDepositAmount", + func(params *types.Params) { + params.MinInitDepositAmount = sdk.NewInt(0) + }, + "minimum initial deposit amount must be positive: 0", + }, + { + "NilInitPoolCoinMintAmount", + func(params *types.Params) { + params.InitPoolCoinMintAmount = sdk.Int{} + }, + "initial pool coin mint amount must not be nil", + }, + { + "NonPositiveInitPoolCoinMintAmount", + func(params *types.Params) { + params.InitPoolCoinMintAmount = sdk.ZeroInt() + }, + "initial pool coin mint amount must be positive: 0", + }, + { + "TooSmallInitPoolCoinMintAmount", + func(params *types.Params) { + params.InitPoolCoinMintAmount = sdk.NewInt(10) + }, + "initial pool coin mint amount must be greater than or equal to 1000000: 10", + }, + { + "NilMaxReserveCoinAmount", + func(params *types.Params) { + params.MaxReserveCoinAmount = sdk.Int{} + }, + "max reserve coin amount must not be nil", + }, + { + "NegativeMaxReserveCoinAmount", + func(params *types.Params) { + params.MaxReserveCoinAmount = sdk.NewInt(-1) + }, + "max reserve coin amount must not be negative: -1", + }, + { + "NilSwapFeeRate", + func(params *types.Params) { + params.SwapFeeRate = sdk.Dec{} + }, + "swap fee rate must not be nil", + }, + { + "NegativeSwapFeeRate", + func(params *types.Params) { + params.SwapFeeRate = sdk.NewDec(-1) + }, + "swap fee rate must not be negative: -1.000000000000000000", + }, + { + "TooLargeSwapFeeRate", + func(params *types.Params) { + params.SwapFeeRate = sdk.NewDec(2) + }, + "swap fee rate too large: 2.000000000000000000", + }, + { + "NilWithdrawFeeRate", + func(params *types.Params) { + params.WithdrawFeeRate = sdk.Dec{} + }, + "withdraw fee rate must not be nil", + }, + { + "NegativeWithdrawFeeRate", + func(params *types.Params) { + params.WithdrawFeeRate = sdk.NewDec(-1) + }, + "withdraw fee rate must not be negative: -1.000000000000000000", + }, + { + "TooLargeWithdrawFeeRate", + func(params *types.Params) { + params.WithdrawFeeRate = sdk.NewDec(2) + }, + "withdraw fee rate too large: 2.000000000000000000", + }, + { + "NilMaxOrderAmountRatio", + func(params *types.Params) { + params.MaxOrderAmountRatio = sdk.Dec{} + }, + "max order amount ratio must not be nil", + }, + { + "NegativeMaxOrderAmountRatio", + func(params *types.Params) { + params.MaxOrderAmountRatio = sdk.NewDec(-1) + }, + "max order amount ratio must not be negative: -1.000000000000000000", + }, + { + "TooLargeMaxOrderAmountRatio", + func(params *types.Params) { + params.MaxOrderAmountRatio = sdk.NewDec(2) + }, + "max order amount ratio too large: 2.000000000000000000", + }, + { + "EmptyPoolCreationFee", + func(params *types.Params) { + params.PoolCreationFee = sdk.NewCoins() + }, + "pool creation fee must not be empty", + }, + { + "InvalidPoolCreationFeeDenom", + func(params *types.Params) { + params.PoolCreationFee = sdk.Coins{ + sdk.Coin{ + Denom: "invalid denom---", + Amount: params.PoolCreationFee.AmountOf(params.PoolCreationFee.GetDenomByIndex(0)), + }, + } + }, + "invalid denom: invalid denom---", + }, + { + "NotPositivePoolCreationFeeAmount", + func(params *types.Params) { + params.PoolCreationFee = sdk.Coins{ + sdk.Coin{ + Denom: params.PoolCreationFee.GetDenomByIndex(0), + Amount: sdk.ZeroInt(), + }, + } + }, + "coin 0stake amount is not positive", + }, + { + "NonPositiveUnitBatchHeight", + func(params *types.Params) { + params.UnitBatchHeight = 0 + }, + "unit batch height must be positive: 0", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + params := types.DefaultParams() + tc.configure(¶ms) + err := params.Validate() + require.EqualError(t, err, tc.errString) + var err2 error + for _, p := range params.ParamSetPairs() { + err := p.ValidatorFn(reflect.ValueOf(p.Value).Elem().Interface()) + if err != nil { + err2 = err + break + } + } + require.EqualError(t, err2, tc.errString) + }) + } +} diff --git a/x/liquidity/types/querier.go b/x/liquidity/types/querier.go new file mode 100644 index 00000000000..1db17f1941c --- /dev/null +++ b/x/liquidity/types/querier.go @@ -0,0 +1,33 @@ +package types + +// DONTCOVER +// client is excluded from test coverage in the poc phase milestone 1 and will be included in milestone 2 with completeness + +// QueryLiquidityPool liquidity query endpoint supported by the liquidity querier +const ( + QueryLiquidityPool = "liquidityPool" + QueryLiquidityPools = "liquidityPools" +) + +// QueryLiquidityPoolParams is the query parameters for 'custom/liquidity' +type QueryLiquidityPoolParams struct { + PoolId uint64 `json:"pool_id" yaml:"pool_id"` //nolint:revive +} + +// return params of Liquidity Pool Query +func NewQueryLiquidityPoolParams(poolID uint64) QueryLiquidityPoolParams { + return QueryLiquidityPoolParams{ + PoolId: poolID, + } +} + +// QueryValidatorsParams defines the params for the following queries: +// - 'custom/liquidity/liquidityPools' +type QueryLiquidityPoolsParams struct { + Page, Limit int +} + +// return params of Liquidity Pools Query +func NewQueryLiquidityPoolsParams(page, limit int) QueryLiquidityPoolsParams { + return QueryLiquidityPoolsParams{page, limit} +} diff --git a/x/liquidity/types/query.go b/x/liquidity/types/query.go new file mode 100644 index 00000000000..221c91b54f9 --- /dev/null +++ b/x/liquidity/types/query.go @@ -0,0 +1,4 @@ +package types + +// DONTCOVER +// client is excluded from test coverage in the poc phase milestone 1 and will be included in milestone 2 with completeness diff --git a/x/liquidity/types/query.pb.go b/x/liquidity/types/query.pb.go new file mode 100644 index 00000000000..930781481f9 --- /dev/null +++ b/x/liquidity/types/query.pb.go @@ -0,0 +1,4963 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tendermint/liquidity/v1beta1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + query "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + _ "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 + +// the request type for the QueryLiquidityPool RPC method. requestable specified pool_id. +type QueryLiquidityPoolRequest struct { + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` +} + +func (m *QueryLiquidityPoolRequest) Reset() { *m = QueryLiquidityPoolRequest{} } +func (m *QueryLiquidityPoolRequest) String() string { return proto.CompactTextString(m) } +func (*QueryLiquidityPoolRequest) ProtoMessage() {} +func (*QueryLiquidityPoolRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{0} +} +func (m *QueryLiquidityPoolRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryLiquidityPoolRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryLiquidityPoolRequest.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 *QueryLiquidityPoolRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryLiquidityPoolRequest.Merge(m, src) +} +func (m *QueryLiquidityPoolRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryLiquidityPoolRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryLiquidityPoolRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryLiquidityPoolRequest proto.InternalMessageInfo + +func (m *QueryLiquidityPoolRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +// the response type for the QueryLiquidityPoolResponse RPC method. Returns the liquidity pool that corresponds to the requested pool_id. +type QueryLiquidityPoolResponse struct { + Pool Pool `protobuf:"bytes,1,opt,name=pool,proto3" json:"pool"` +} + +func (m *QueryLiquidityPoolResponse) Reset() { *m = QueryLiquidityPoolResponse{} } +func (m *QueryLiquidityPoolResponse) String() string { return proto.CompactTextString(m) } +func (*QueryLiquidityPoolResponse) ProtoMessage() {} +func (*QueryLiquidityPoolResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{1} +} +func (m *QueryLiquidityPoolResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryLiquidityPoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryLiquidityPoolResponse.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 *QueryLiquidityPoolResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryLiquidityPoolResponse.Merge(m, src) +} +func (m *QueryLiquidityPoolResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryLiquidityPoolResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryLiquidityPoolResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryLiquidityPoolResponse proto.InternalMessageInfo + +func (m *QueryLiquidityPoolResponse) GetPool() Pool { + if m != nil { + return m.Pool + } + return Pool{} +} + +// the request type for the QueryLiquidityByPoolCoinDenomPool RPC method. Requestable specified pool_coin_denom. +type QueryLiquidityPoolByPoolCoinDenomRequest struct { + PoolCoinDenom string `protobuf:"bytes,1,opt,name=pool_coin_denom,json=poolCoinDenom,proto3" json:"pool_coin_denom,omitempty"` +} + +func (m *QueryLiquidityPoolByPoolCoinDenomRequest) Reset() { + *m = QueryLiquidityPoolByPoolCoinDenomRequest{} +} +func (m *QueryLiquidityPoolByPoolCoinDenomRequest) String() string { return proto.CompactTextString(m) } +func (*QueryLiquidityPoolByPoolCoinDenomRequest) ProtoMessage() {} +func (*QueryLiquidityPoolByPoolCoinDenomRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{2} +} +func (m *QueryLiquidityPoolByPoolCoinDenomRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryLiquidityPoolByPoolCoinDenomRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryLiquidityPoolByPoolCoinDenomRequest.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 *QueryLiquidityPoolByPoolCoinDenomRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryLiquidityPoolByPoolCoinDenomRequest.Merge(m, src) +} +func (m *QueryLiquidityPoolByPoolCoinDenomRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryLiquidityPoolByPoolCoinDenomRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryLiquidityPoolByPoolCoinDenomRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryLiquidityPoolByPoolCoinDenomRequest proto.InternalMessageInfo + +func (m *QueryLiquidityPoolByPoolCoinDenomRequest) GetPoolCoinDenom() string { + if m != nil { + return m.PoolCoinDenom + } + return "" +} + +// the request type for the QueryLiquidityByReserveAcc RPC method. Requestable specified reserve_acc. +type QueryLiquidityPoolByReserveAccRequest struct { + ReserveAcc string `protobuf:"bytes,1,opt,name=reserve_acc,json=reserveAcc,proto3" json:"reserve_acc,omitempty"` +} + +func (m *QueryLiquidityPoolByReserveAccRequest) Reset() { *m = QueryLiquidityPoolByReserveAccRequest{} } +func (m *QueryLiquidityPoolByReserveAccRequest) String() string { return proto.CompactTextString(m) } +func (*QueryLiquidityPoolByReserveAccRequest) ProtoMessage() {} +func (*QueryLiquidityPoolByReserveAccRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{3} +} +func (m *QueryLiquidityPoolByReserveAccRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryLiquidityPoolByReserveAccRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryLiquidityPoolByReserveAccRequest.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 *QueryLiquidityPoolByReserveAccRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryLiquidityPoolByReserveAccRequest.Merge(m, src) +} +func (m *QueryLiquidityPoolByReserveAccRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryLiquidityPoolByReserveAccRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryLiquidityPoolByReserveAccRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryLiquidityPoolByReserveAccRequest proto.InternalMessageInfo + +func (m *QueryLiquidityPoolByReserveAccRequest) GetReserveAcc() string { + if m != nil { + return m.ReserveAcc + } + return "" +} + +// the request type for the QueryLiquidityPoolBatch RPC method. requestable including specified pool_id. +type QueryLiquidityPoolBatchRequest struct { + // id of the target pool for query + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` +} + +func (m *QueryLiquidityPoolBatchRequest) Reset() { *m = QueryLiquidityPoolBatchRequest{} } +func (m *QueryLiquidityPoolBatchRequest) String() string { return proto.CompactTextString(m) } +func (*QueryLiquidityPoolBatchRequest) ProtoMessage() {} +func (*QueryLiquidityPoolBatchRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{4} +} +func (m *QueryLiquidityPoolBatchRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryLiquidityPoolBatchRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryLiquidityPoolBatchRequest.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 *QueryLiquidityPoolBatchRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryLiquidityPoolBatchRequest.Merge(m, src) +} +func (m *QueryLiquidityPoolBatchRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryLiquidityPoolBatchRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryLiquidityPoolBatchRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryLiquidityPoolBatchRequest proto.InternalMessageInfo + +func (m *QueryLiquidityPoolBatchRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +// the response type for the QueryLiquidityPoolBatchResponse RPC method. Returns the liquidity pool batch that corresponds to the requested pool_id. +type QueryLiquidityPoolBatchResponse struct { + Batch PoolBatch `protobuf:"bytes,1,opt,name=batch,proto3" json:"batch"` +} + +func (m *QueryLiquidityPoolBatchResponse) Reset() { *m = QueryLiquidityPoolBatchResponse{} } +func (m *QueryLiquidityPoolBatchResponse) String() string { return proto.CompactTextString(m) } +func (*QueryLiquidityPoolBatchResponse) ProtoMessage() {} +func (*QueryLiquidityPoolBatchResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{5} +} +func (m *QueryLiquidityPoolBatchResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryLiquidityPoolBatchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryLiquidityPoolBatchResponse.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 *QueryLiquidityPoolBatchResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryLiquidityPoolBatchResponse.Merge(m, src) +} +func (m *QueryLiquidityPoolBatchResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryLiquidityPoolBatchResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryLiquidityPoolBatchResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryLiquidityPoolBatchResponse proto.InternalMessageInfo + +func (m *QueryLiquidityPoolBatchResponse) GetBatch() PoolBatch { + if m != nil { + return m.Batch + } + return PoolBatch{} +} + +// the request type for the QueryLiquidityPools RPC method. Requestable including pagination offset, limit, key. +type QueryLiquidityPoolsRequest struct { + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryLiquidityPoolsRequest) Reset() { *m = QueryLiquidityPoolsRequest{} } +func (m *QueryLiquidityPoolsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryLiquidityPoolsRequest) ProtoMessage() {} +func (*QueryLiquidityPoolsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{6} +} +func (m *QueryLiquidityPoolsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryLiquidityPoolsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryLiquidityPoolsRequest.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 *QueryLiquidityPoolsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryLiquidityPoolsRequest.Merge(m, src) +} +func (m *QueryLiquidityPoolsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryLiquidityPoolsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryLiquidityPoolsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryLiquidityPoolsRequest proto.InternalMessageInfo + +func (m *QueryLiquidityPoolsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// the response type for the QueryLiquidityPoolsResponse RPC method. This includes a list of all existing liquidity pools and paging results that contain next_key and total count. +type QueryLiquidityPoolsResponse struct { + Pools []Pool `protobuf:"bytes,1,rep,name=pools,proto3" json:"pools"` + // pagination defines the pagination in the response. not working on this version. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryLiquidityPoolsResponse) Reset() { *m = QueryLiquidityPoolsResponse{} } +func (m *QueryLiquidityPoolsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryLiquidityPoolsResponse) ProtoMessage() {} +func (*QueryLiquidityPoolsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{7} +} +func (m *QueryLiquidityPoolsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryLiquidityPoolsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryLiquidityPoolsResponse.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 *QueryLiquidityPoolsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryLiquidityPoolsResponse.Merge(m, src) +} +func (m *QueryLiquidityPoolsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryLiquidityPoolsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryLiquidityPoolsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryLiquidityPoolsResponse proto.InternalMessageInfo + +func (m *QueryLiquidityPoolsResponse) GetPools() []Pool { + if m != nil { + return m.Pools + } + return nil +} + +func (m *QueryLiquidityPoolsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryParamsRequest is request type for the QueryParams 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_f8c9321d314a3b1d, []int{8} +} +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 + +// the response type for the QueryParamsResponse RPC method. This includes current parameter of the liquidity module. +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_f8c9321d314a3b1d, []int{9} +} +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{} +} + +// the request type for the QueryPoolBatchSwapMsgs RPC method. Requestable including specified pool_id and pagination offset, limit, key. +type QueryPoolBatchSwapMsgsRequest struct { + // id of the target pool for query + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryPoolBatchSwapMsgsRequest) Reset() { *m = QueryPoolBatchSwapMsgsRequest{} } +func (m *QueryPoolBatchSwapMsgsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchSwapMsgsRequest) ProtoMessage() {} +func (*QueryPoolBatchSwapMsgsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{10} +} +func (m *QueryPoolBatchSwapMsgsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchSwapMsgsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchSwapMsgsRequest.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 *QueryPoolBatchSwapMsgsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchSwapMsgsRequest.Merge(m, src) +} +func (m *QueryPoolBatchSwapMsgsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchSwapMsgsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchSwapMsgsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchSwapMsgsRequest proto.InternalMessageInfo + +func (m *QueryPoolBatchSwapMsgsRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *QueryPoolBatchSwapMsgsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// the request type for the QueryPoolBatchSwap RPC method. Requestable including specified pool_id and msg_index. +type QueryPoolBatchSwapMsgRequest struct { + // id of the target pool for query + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // target msg_index of the pool + MsgIndex uint64 `protobuf:"varint,2,opt,name=msg_index,json=msgIndex,proto3" json:"msg_index,omitempty"` +} + +func (m *QueryPoolBatchSwapMsgRequest) Reset() { *m = QueryPoolBatchSwapMsgRequest{} } +func (m *QueryPoolBatchSwapMsgRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchSwapMsgRequest) ProtoMessage() {} +func (*QueryPoolBatchSwapMsgRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{11} +} +func (m *QueryPoolBatchSwapMsgRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchSwapMsgRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchSwapMsgRequest.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 *QueryPoolBatchSwapMsgRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchSwapMsgRequest.Merge(m, src) +} +func (m *QueryPoolBatchSwapMsgRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchSwapMsgRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchSwapMsgRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchSwapMsgRequest proto.InternalMessageInfo + +func (m *QueryPoolBatchSwapMsgRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *QueryPoolBatchSwapMsgRequest) GetMsgIndex() uint64 { + if m != nil { + return m.MsgIndex + } + return 0 +} + +// the response type for the QueryPoolBatchSwapMsgs RPC method. This includes list of all currently existing swap messages of the batch and paging results that contain next_key and total count. +type QueryPoolBatchSwapMsgsResponse struct { + Swaps []SwapMsgState `protobuf:"bytes,1,rep,name=swaps,proto3" json:"swaps"` + // pagination defines the pagination in the response. not working on this version. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryPoolBatchSwapMsgsResponse) Reset() { *m = QueryPoolBatchSwapMsgsResponse{} } +func (m *QueryPoolBatchSwapMsgsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchSwapMsgsResponse) ProtoMessage() {} +func (*QueryPoolBatchSwapMsgsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{12} +} +func (m *QueryPoolBatchSwapMsgsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchSwapMsgsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchSwapMsgsResponse.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 *QueryPoolBatchSwapMsgsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchSwapMsgsResponse.Merge(m, src) +} +func (m *QueryPoolBatchSwapMsgsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchSwapMsgsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchSwapMsgsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchSwapMsgsResponse proto.InternalMessageInfo + +func (m *QueryPoolBatchSwapMsgsResponse) GetSwaps() []SwapMsgState { + if m != nil { + return m.Swaps + } + return nil +} + +func (m *QueryPoolBatchSwapMsgsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +// the response type for the QueryPoolBatchSwapMsg RPC method. This includes a batch swap message of the batch. +type QueryPoolBatchSwapMsgResponse struct { + Swap SwapMsgState `protobuf:"bytes,1,opt,name=swap,proto3" json:"swap"` +} + +func (m *QueryPoolBatchSwapMsgResponse) Reset() { *m = QueryPoolBatchSwapMsgResponse{} } +func (m *QueryPoolBatchSwapMsgResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchSwapMsgResponse) ProtoMessage() {} +func (*QueryPoolBatchSwapMsgResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{13} +} +func (m *QueryPoolBatchSwapMsgResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchSwapMsgResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchSwapMsgResponse.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 *QueryPoolBatchSwapMsgResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchSwapMsgResponse.Merge(m, src) +} +func (m *QueryPoolBatchSwapMsgResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchSwapMsgResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchSwapMsgResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchSwapMsgResponse proto.InternalMessageInfo + +func (m *QueryPoolBatchSwapMsgResponse) GetSwap() SwapMsgState { + if m != nil { + return m.Swap + } + return SwapMsgState{} +} + +// the request type for the QueryPoolBatchDeposit RPC method. Requestable including specified pool_id and pagination offset, limit, key. +type QueryPoolBatchDepositMsgsRequest struct { + // id of the target pool for query + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryPoolBatchDepositMsgsRequest) Reset() { *m = QueryPoolBatchDepositMsgsRequest{} } +func (m *QueryPoolBatchDepositMsgsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchDepositMsgsRequest) ProtoMessage() {} +func (*QueryPoolBatchDepositMsgsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{14} +} +func (m *QueryPoolBatchDepositMsgsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchDepositMsgsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchDepositMsgsRequest.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 *QueryPoolBatchDepositMsgsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchDepositMsgsRequest.Merge(m, src) +} +func (m *QueryPoolBatchDepositMsgsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchDepositMsgsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchDepositMsgsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchDepositMsgsRequest proto.InternalMessageInfo + +func (m *QueryPoolBatchDepositMsgsRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *QueryPoolBatchDepositMsgsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// the request type for the QueryPoolBatchDeposit RPC method. requestable including specified pool_id and msg_index. +type QueryPoolBatchDepositMsgRequest struct { + // id of the target pool for query + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // target msg_index of the pool + MsgIndex uint64 `protobuf:"varint,2,opt,name=msg_index,json=msgIndex,proto3" json:"msg_index,omitempty"` +} + +func (m *QueryPoolBatchDepositMsgRequest) Reset() { *m = QueryPoolBatchDepositMsgRequest{} } +func (m *QueryPoolBatchDepositMsgRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchDepositMsgRequest) ProtoMessage() {} +func (*QueryPoolBatchDepositMsgRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{15} +} +func (m *QueryPoolBatchDepositMsgRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchDepositMsgRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchDepositMsgRequest.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 *QueryPoolBatchDepositMsgRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchDepositMsgRequest.Merge(m, src) +} +func (m *QueryPoolBatchDepositMsgRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchDepositMsgRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchDepositMsgRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchDepositMsgRequest proto.InternalMessageInfo + +func (m *QueryPoolBatchDepositMsgRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *QueryPoolBatchDepositMsgRequest) GetMsgIndex() uint64 { + if m != nil { + return m.MsgIndex + } + return 0 +} + +// the response type for the QueryPoolBatchDeposit RPC method. This includes a list of all currently existing deposit messages of the batch and paging results that contain next_key and total count. +type QueryPoolBatchDepositMsgsResponse struct { + Deposits []DepositMsgState `protobuf:"bytes,1,rep,name=deposits,proto3" json:"deposits"` + // pagination defines the pagination in the response. not working on this version. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryPoolBatchDepositMsgsResponse) Reset() { *m = QueryPoolBatchDepositMsgsResponse{} } +func (m *QueryPoolBatchDepositMsgsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchDepositMsgsResponse) ProtoMessage() {} +func (*QueryPoolBatchDepositMsgsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{16} +} +func (m *QueryPoolBatchDepositMsgsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchDepositMsgsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchDepositMsgsResponse.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 *QueryPoolBatchDepositMsgsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchDepositMsgsResponse.Merge(m, src) +} +func (m *QueryPoolBatchDepositMsgsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchDepositMsgsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchDepositMsgsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchDepositMsgsResponse proto.InternalMessageInfo + +func (m *QueryPoolBatchDepositMsgsResponse) GetDeposits() []DepositMsgState { + if m != nil { + return m.Deposits + } + return nil +} + +func (m *QueryPoolBatchDepositMsgsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +// the response type for the QueryPoolBatchDepositMsg RPC method. This includes a batch swap message of the batch. +type QueryPoolBatchDepositMsgResponse struct { + Deposit DepositMsgState `protobuf:"bytes,1,opt,name=deposit,proto3" json:"deposit"` +} + +func (m *QueryPoolBatchDepositMsgResponse) Reset() { *m = QueryPoolBatchDepositMsgResponse{} } +func (m *QueryPoolBatchDepositMsgResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchDepositMsgResponse) ProtoMessage() {} +func (*QueryPoolBatchDepositMsgResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{17} +} +func (m *QueryPoolBatchDepositMsgResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchDepositMsgResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchDepositMsgResponse.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 *QueryPoolBatchDepositMsgResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchDepositMsgResponse.Merge(m, src) +} +func (m *QueryPoolBatchDepositMsgResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchDepositMsgResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchDepositMsgResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchDepositMsgResponse proto.InternalMessageInfo + +func (m *QueryPoolBatchDepositMsgResponse) GetDeposit() DepositMsgState { + if m != nil { + return m.Deposit + } + return DepositMsgState{} +} + +// the request type for the QueryPoolBatchWithdraw RPC method. Requestable including specified pool_id and pagination offset, limit, key. +type QueryPoolBatchWithdrawMsgsRequest struct { + // id of the target pool for query + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryPoolBatchWithdrawMsgsRequest) Reset() { *m = QueryPoolBatchWithdrawMsgsRequest{} } +func (m *QueryPoolBatchWithdrawMsgsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchWithdrawMsgsRequest) ProtoMessage() {} +func (*QueryPoolBatchWithdrawMsgsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{18} +} +func (m *QueryPoolBatchWithdrawMsgsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchWithdrawMsgsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchWithdrawMsgsRequest.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 *QueryPoolBatchWithdrawMsgsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchWithdrawMsgsRequest.Merge(m, src) +} +func (m *QueryPoolBatchWithdrawMsgsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchWithdrawMsgsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchWithdrawMsgsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchWithdrawMsgsRequest proto.InternalMessageInfo + +func (m *QueryPoolBatchWithdrawMsgsRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *QueryPoolBatchWithdrawMsgsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// the request type for the QueryPoolBatchWithdraw RPC method. requestable including specified pool_id and msg_index. +type QueryPoolBatchWithdrawMsgRequest struct { + // id of the target pool for query + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // target msg_index of the pool + MsgIndex uint64 `protobuf:"varint,2,opt,name=msg_index,json=msgIndex,proto3" json:"msg_index,omitempty"` +} + +func (m *QueryPoolBatchWithdrawMsgRequest) Reset() { *m = QueryPoolBatchWithdrawMsgRequest{} } +func (m *QueryPoolBatchWithdrawMsgRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchWithdrawMsgRequest) ProtoMessage() {} +func (*QueryPoolBatchWithdrawMsgRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{19} +} +func (m *QueryPoolBatchWithdrawMsgRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchWithdrawMsgRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchWithdrawMsgRequest.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 *QueryPoolBatchWithdrawMsgRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchWithdrawMsgRequest.Merge(m, src) +} +func (m *QueryPoolBatchWithdrawMsgRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchWithdrawMsgRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchWithdrawMsgRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchWithdrawMsgRequest proto.InternalMessageInfo + +func (m *QueryPoolBatchWithdrawMsgRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *QueryPoolBatchWithdrawMsgRequest) GetMsgIndex() uint64 { + if m != nil { + return m.MsgIndex + } + return 0 +} + +// the response type for the QueryPoolBatchWithdraw RPC method. This includes a list of all currently existing withdraw messages of the batch and paging results that contain next_key and total count. +type QueryPoolBatchWithdrawMsgsResponse struct { + Withdraws []WithdrawMsgState `protobuf:"bytes,1,rep,name=withdraws,proto3" json:"withdraws"` + // pagination defines the pagination in the response. Not supported on this version. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryPoolBatchWithdrawMsgsResponse) Reset() { *m = QueryPoolBatchWithdrawMsgsResponse{} } +func (m *QueryPoolBatchWithdrawMsgsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchWithdrawMsgsResponse) ProtoMessage() {} +func (*QueryPoolBatchWithdrawMsgsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{20} +} +func (m *QueryPoolBatchWithdrawMsgsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchWithdrawMsgsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchWithdrawMsgsResponse.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 *QueryPoolBatchWithdrawMsgsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchWithdrawMsgsResponse.Merge(m, src) +} +func (m *QueryPoolBatchWithdrawMsgsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchWithdrawMsgsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchWithdrawMsgsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchWithdrawMsgsResponse proto.InternalMessageInfo + +func (m *QueryPoolBatchWithdrawMsgsResponse) GetWithdraws() []WithdrawMsgState { + if m != nil { + return m.Withdraws + } + return nil +} + +func (m *QueryPoolBatchWithdrawMsgsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +// the response type for the QueryPoolBatchWithdrawMsg RPC method. This includes a batch swap message of the batch. +type QueryPoolBatchWithdrawMsgResponse struct { + Withdraw WithdrawMsgState `protobuf:"bytes,1,opt,name=withdraw,proto3" json:"withdraw"` +} + +func (m *QueryPoolBatchWithdrawMsgResponse) Reset() { *m = QueryPoolBatchWithdrawMsgResponse{} } +func (m *QueryPoolBatchWithdrawMsgResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPoolBatchWithdrawMsgResponse) ProtoMessage() {} +func (*QueryPoolBatchWithdrawMsgResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f8c9321d314a3b1d, []int{21} +} +func (m *QueryPoolBatchWithdrawMsgResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPoolBatchWithdrawMsgResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPoolBatchWithdrawMsgResponse.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 *QueryPoolBatchWithdrawMsgResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPoolBatchWithdrawMsgResponse.Merge(m, src) +} +func (m *QueryPoolBatchWithdrawMsgResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPoolBatchWithdrawMsgResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPoolBatchWithdrawMsgResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPoolBatchWithdrawMsgResponse proto.InternalMessageInfo + +func (m *QueryPoolBatchWithdrawMsgResponse) GetWithdraw() WithdrawMsgState { + if m != nil { + return m.Withdraw + } + return WithdrawMsgState{} +} + +func init() { + proto.RegisterType((*QueryLiquidityPoolRequest)(nil), "tendermint.liquidity.v1beta1.QueryLiquidityPoolRequest") + proto.RegisterType((*QueryLiquidityPoolResponse)(nil), "tendermint.liquidity.v1beta1.QueryLiquidityPoolResponse") + proto.RegisterType((*QueryLiquidityPoolByPoolCoinDenomRequest)(nil), "tendermint.liquidity.v1beta1.QueryLiquidityPoolByPoolCoinDenomRequest") + proto.RegisterType((*QueryLiquidityPoolByReserveAccRequest)(nil), "tendermint.liquidity.v1beta1.QueryLiquidityPoolByReserveAccRequest") + proto.RegisterType((*QueryLiquidityPoolBatchRequest)(nil), "tendermint.liquidity.v1beta1.QueryLiquidityPoolBatchRequest") + proto.RegisterType((*QueryLiquidityPoolBatchResponse)(nil), "tendermint.liquidity.v1beta1.QueryLiquidityPoolBatchResponse") + proto.RegisterType((*QueryLiquidityPoolsRequest)(nil), "tendermint.liquidity.v1beta1.QueryLiquidityPoolsRequest") + proto.RegisterType((*QueryLiquidityPoolsResponse)(nil), "tendermint.liquidity.v1beta1.QueryLiquidityPoolsResponse") + proto.RegisterType((*QueryParamsRequest)(nil), "tendermint.liquidity.v1beta1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "tendermint.liquidity.v1beta1.QueryParamsResponse") + proto.RegisterType((*QueryPoolBatchSwapMsgsRequest)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchSwapMsgsRequest") + proto.RegisterType((*QueryPoolBatchSwapMsgRequest)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchSwapMsgRequest") + proto.RegisterType((*QueryPoolBatchSwapMsgsResponse)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchSwapMsgsResponse") + proto.RegisterType((*QueryPoolBatchSwapMsgResponse)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchSwapMsgResponse") + proto.RegisterType((*QueryPoolBatchDepositMsgsRequest)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchDepositMsgsRequest") + proto.RegisterType((*QueryPoolBatchDepositMsgRequest)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchDepositMsgRequest") + proto.RegisterType((*QueryPoolBatchDepositMsgsResponse)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchDepositMsgsResponse") + proto.RegisterType((*QueryPoolBatchDepositMsgResponse)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchDepositMsgResponse") + proto.RegisterType((*QueryPoolBatchWithdrawMsgsRequest)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchWithdrawMsgsRequest") + proto.RegisterType((*QueryPoolBatchWithdrawMsgRequest)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchWithdrawMsgRequest") + proto.RegisterType((*QueryPoolBatchWithdrawMsgsResponse)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchWithdrawMsgsResponse") + proto.RegisterType((*QueryPoolBatchWithdrawMsgResponse)(nil), "tendermint.liquidity.v1beta1.QueryPoolBatchWithdrawMsgResponse") +} + +func init() { + proto.RegisterFile("tendermint/liquidity/v1beta1/query.proto", fileDescriptor_f8c9321d314a3b1d) +} + +var fileDescriptor_f8c9321d314a3b1d = []byte{ + // 1984 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x9a, 0x5f, 0x8c, 0xdc, 0x46, + 0x19, 0xc0, 0xe3, 0x8b, 0x77, 0x9b, 0x4c, 0x54, 0x28, 0xd3, 0x54, 0xb4, 0x6e, 0x7a, 0x99, 0x5a, + 0xd0, 0x84, 0x72, 0x67, 0xe7, 0xf2, 0x47, 0x4d, 0x36, 0xb9, 0x94, 0xbd, 0xbb, 0x5e, 0x49, 0x44, + 0x4a, 0xd8, 0x14, 0x0a, 0x29, 0xe8, 0x98, 0xb3, 0x27, 0x3e, 0x83, 0x77, 0xc6, 0xf1, 0xcc, 0xee, + 0xdd, 0x71, 0x9c, 0x14, 0xfe, 0x48, 0xa5, 0x2f, 0x25, 0x5a, 0x04, 0x42, 0x48, 0x44, 0x20, 0x44, + 0x29, 0x6a, 0x11, 0x02, 0xc1, 0x5b, 0x11, 0x2a, 0x08, 0x5a, 0x1e, 0x90, 0x8a, 0xfa, 0xc2, 0x0b, + 0x08, 0x12, 0x5e, 0x78, 0x42, 0xbc, 0xf2, 0x84, 0x6c, 0x8f, 0x77, 0xbd, 0xbb, 0xde, 0xdd, 0xb3, + 0x2f, 0xf4, 0xa8, 0xb2, 0x2f, 0xc9, 0xad, 0x3d, 0xdf, 0x37, 0xdf, 0x9f, 0xdf, 0x37, 0xdf, 0x78, + 0x6c, 0x70, 0x58, 0x10, 0x6a, 0x93, 0xa0, 0xee, 0x52, 0x61, 0x7a, 0xee, 0xd5, 0x86, 0x6b, 0xbb, + 0x62, 0xdd, 0x6c, 0xce, 0x2c, 0x13, 0x81, 0x67, 0xcc, 0xab, 0x0d, 0x12, 0xac, 0x1b, 0x7e, 0xc0, + 0x04, 0x83, 0x07, 0x3a, 0x23, 0x8d, 0xf6, 0x48, 0x43, 0x8e, 0xd4, 0xf6, 0x3b, 0xcc, 0x61, 0xd1, + 0x40, 0x33, 0xfc, 0x2b, 0x96, 0xd1, 0xa6, 0x86, 0x6a, 0xef, 0x68, 0x89, 0x47, 0x1f, 0x70, 0x18, + 0x73, 0x3c, 0x62, 0x62, 0xdf, 0x35, 0x31, 0xa5, 0x4c, 0x60, 0xe1, 0x32, 0xca, 0xe5, 0xdd, 0x87, + 0x2c, 0xc6, 0xeb, 0x8c, 0x2f, 0xc5, 0x93, 0xf8, 0xd8, 0x71, 0x69, 0x74, 0x5f, 0xde, 0x8e, 0xff, + 0xb3, 0xa6, 0x1d, 0x42, 0xa7, 0x99, 0x4f, 0x28, 0xf6, 0xdd, 0xe6, 0x51, 0x93, 0xf9, 0x91, 0x8a, + 0x7e, 0x75, 0xfa, 0x71, 0xf0, 0xc0, 0xc7, 0x42, 0xef, 0x3e, 0x92, 0x18, 0x71, 0x91, 0x31, 0xaf, + 0x46, 0xae, 0x36, 0x08, 0x17, 0xf0, 0xbd, 0xe0, 0x2e, 0x9f, 0x31, 0x6f, 0xc9, 0xb5, 0xef, 0x57, + 0x90, 0x72, 0x58, 0xad, 0x95, 0xc3, 0x9f, 0xe7, 0x6c, 0xfd, 0x32, 0xd0, 0xb2, 0xa4, 0xb8, 0xcf, + 0x28, 0x27, 0xf0, 0x0c, 0x50, 0xc3, 0x71, 0x91, 0xcc, 0xbe, 0xa3, 0xba, 0x31, 0x2c, 0x62, 0x46, + 0x28, 0x39, 0xa7, 0xbe, 0xf1, 0xd7, 0x83, 0xbb, 0x6a, 0x91, 0x94, 0x5e, 0x03, 0x87, 0xfb, 0x75, + 0xcf, 0x45, 0xff, 0xce, 0x33, 0x97, 0x2e, 0x10, 0xca, 0xea, 0x89, 0x81, 0x8f, 0x80, 0x77, 0x47, + 0x06, 0x5a, 0xcc, 0xa5, 0x4b, 0x76, 0x78, 0x27, 0x9a, 0x74, 0x6f, 0xed, 0x6e, 0x3f, 0x3d, 0x5c, + 0xff, 0x30, 0x78, 0x7f, 0x96, 0xce, 0x1a, 0xe1, 0x24, 0x68, 0x92, 0xaa, 0x65, 0x25, 0x0a, 0x0f, + 0x82, 0x7d, 0x41, 0x7c, 0x71, 0x09, 0x5b, 0x96, 0x54, 0x06, 0x82, 0xf6, 0x38, 0xfd, 0x14, 0x98, + 0xcc, 0xd0, 0x84, 0x85, 0xb5, 0x32, 0x32, 0x68, 0x57, 0xc0, 0xc1, 0x81, 0xa2, 0x32, 0x72, 0xf3, + 0xa0, 0xb4, 0x1c, 0x5e, 0x90, 0xa1, 0x3b, 0xb4, 0x85, 0xd0, 0x85, 0xc3, 0x65, 0xfc, 0x62, 0x59, + 0xdd, 0xce, 0x4a, 0x0e, 0x4f, 0xcc, 0x5b, 0x04, 0xa0, 0x03, 0x8d, 0x9c, 0xe7, 0x11, 0x23, 0x86, + 0xca, 0x58, 0xc6, 0x9c, 0x18, 0x31, 0xed, 0xed, 0x49, 0xb0, 0x43, 0xa4, 0x6c, 0x2d, 0x25, 0xa9, + 0xbf, 0xa8, 0x80, 0x07, 0x33, 0xa7, 0x91, 0xae, 0x9c, 0x05, 0xa5, 0xd0, 0x6f, 0x7e, 0xbf, 0x82, + 0x76, 0xe7, 0xa2, 0x20, 0x16, 0x83, 0x4f, 0x76, 0xd9, 0x39, 0x21, 0xe3, 0x31, 0xca, 0xce, 0x78, + 0xf2, 0x2e, 0x43, 0xf7, 0x03, 0x18, 0xd9, 0x79, 0x11, 0x07, 0xb8, 0x9e, 0x84, 0x41, 0xff, 0x14, + 0xb8, 0xb7, 0xeb, 0xaa, 0xb4, 0x7a, 0x0e, 0x94, 0xfd, 0xe8, 0x8a, 0x8c, 0xcc, 0xfb, 0x46, 0x98, + 0x1d, 0x8d, 0x95, 0x86, 0x4b, 0x49, 0xfd, 0x9a, 0x02, 0x1e, 0x8a, 0x75, 0x27, 0xf9, 0xb9, 0xb4, + 0x8a, 0xfd, 0x0b, 0xdc, 0xe1, 0xa3, 0x10, 0xe9, 0x49, 0xce, 0x44, 0xe1, 0xe4, 0x3c, 0x0d, 0x0e, + 0x64, 0x5a, 0x30, 0xd2, 0x80, 0x07, 0xc1, 0xde, 0x3a, 0x77, 0x96, 0x5c, 0x6a, 0x93, 0xb5, 0x68, + 0x7e, 0xb5, 0xb6, 0xa7, 0xce, 0x9d, 0x73, 0xe1, 0x6f, 0xfd, 0x67, 0x8a, 0x84, 0x3f, 0xc3, 0x31, + 0x19, 0xbf, 0x45, 0x50, 0xe2, 0xab, 0xd8, 0x4f, 0xb2, 0xfe, 0xe8, 0xf0, 0xf0, 0x49, 0xf1, 0x4b, + 0x02, 0x0b, 0x92, 0x64, 0x3f, 0x12, 0xbf, 0x7d, 0xd9, 0x27, 0x03, 0x72, 0xd1, 0xb6, 0x78, 0x01, + 0xa8, 0xe1, 0x94, 0x32, 0xdf, 0xf9, 0x0d, 0x8e, 0xa4, 0xf5, 0xaf, 0x28, 0x00, 0x75, 0xcf, 0xb3, + 0x40, 0x7c, 0xc6, 0x5d, 0xf1, 0xb6, 0xa6, 0xfd, 0x19, 0xb9, 0xc2, 0x64, 0x18, 0xb1, 0xbd, 0xcc, + 0xff, 0x4a, 0x01, 0x0f, 0x0f, 0x71, 0x4f, 0x86, 0xf2, 0xa3, 0x60, 0x8f, 0x1d, 0x5f, 0x4e, 0xf2, + 0x3f, 0x3d, 0x3c, 0x9c, 0x1d, 0x25, 0xe9, 0x88, 0xb6, 0x95, 0xdc, 0x3e, 0x0a, 0xae, 0x0e, 0xce, + 0x4e, 0xdb, 0xfa, 0x0b, 0xe0, 0x2e, 0x39, 0xb1, 0x64, 0xa1, 0x90, 0xf1, 0x89, 0x0e, 0xfd, 0xab, + 0x7d, 0x21, 0x7b, 0xc6, 0x15, 0x2b, 0x76, 0x80, 0x57, 0xdf, 0x56, 0x24, 0x3e, 0xd9, 0xeb, 0x79, + 0xca, 0x8a, 0xed, 0x31, 0xf1, 0x9a, 0x02, 0xf4, 0x61, 0x0e, 0xca, 0xb0, 0xd6, 0xc0, 0xde, 0x55, + 0x79, 0x3d, 0xa1, 0xc2, 0x18, 0x1e, 0xd8, 0x94, 0x9a, 0x74, 0x64, 0x3b, 0x6a, 0x6e, 0x1f, 0x17, + 0x8d, 0x21, 0x39, 0x6a, 0x7b, 0x70, 0x11, 0xec, 0x49, 0xa6, 0x96, 0x64, 0x14, 0x73, 0xa0, 0xad, + 0xe5, 0xe8, 0xb5, 0x05, 0x50, 0x8a, 0xe6, 0x85, 0xd7, 0x55, 0xf0, 0xae, 0xee, 0x06, 0x0a, 0x4f, + 0x0e, 0x57, 0x3e, 0xb8, 0xb5, 0x6b, 0xa7, 0x0a, 0x48, 0xc6, 0x3e, 0xea, 0x5f, 0xdb, 0xdd, 0xaa, + 0xfe, 0x65, 0x42, 0x9b, 0xad, 0x11, 0xd1, 0x08, 0x28, 0x47, 0x18, 0x79, 0x2e, 0x17, 0x88, 0x5d, + 0x41, 0xd8, 0xf3, 0x50, 0x5b, 0x17, 0x8a, 0x7a, 0x33, 0x0a, 0x1d, 0x41, 0x9d, 0x30, 0xa2, 0x80, + 0xf0, 0x86, 0x27, 0x0c, 0x9d, 0x83, 0xe9, 0x45, 0x97, 0xda, 0x88, 0x35, 0x04, 0xaa, 0xb3, 0x80, + 0x20, 0xbc, 0x1c, 0xfe, 0x29, 0x56, 0x08, 0x8a, 0x12, 0x82, 0x30, 0xb5, 0x11, 0x09, 0x02, 0x16, + 0x20, 0x8b, 0xd9, 0x84, 0xc3, 0xb9, 0x15, 0x21, 0x7c, 0x5e, 0x31, 0x4d, 0xc7, 0x15, 0x2b, 0x8d, + 0x65, 0xc3, 0x62, 0x75, 0x33, 0x73, 0xaf, 0xbc, 0xec, 0xb1, 0x65, 0xd3, 0x26, 0x4d, 0xe2, 0x31, + 0xdf, 0xb4, 0x99, 0x65, 0x5a, 0x9e, 0x4b, 0xa8, 0x30, 0xea, 0xf6, 0xf9, 0x17, 0x15, 0xb0, 0xfb, + 0xc4, 0x91, 0x23, 0xf0, 0x86, 0x02, 0xee, 0x3b, 0x47, 0x05, 0x09, 0x28, 0xf6, 0xd0, 0xa5, 0x70, + 0xbf, 0x16, 0xa0, 0x27, 0xc2, 0xb9, 0xc2, 0x52, 0xbc, 0x07, 0xfb, 0xbe, 0xe7, 0x5a, 0x91, 0xb9, + 0xe6, 0xe7, 0x38, 0xa3, 0xd0, 0xdf, 0xd0, 0x43, 0x1b, 0xf4, 0xca, 0xd1, 0x29, 0xbd, 0x4e, 0x38, + 0xc7, 0x0e, 0xd1, 0x2b, 0x7a, 0xe0, 0x5b, 0xb1, 0x81, 0x95, 0xc8, 0x42, 0x34, 0x8b, 0x9e, 0x62, + 0x62, 0x91, 0x35, 0xa8, 0x8d, 0x6c, 0xc2, 0x2d, 0x34, 0x8b, 0x9e, 0x5e, 0x21, 0xa1, 0x63, 0x01, + 0x41, 0x94, 0xc9, 0x70, 0xf8, 0xe1, 0xfe, 0x90, 0x0a, 0xa3, 0x82, 0x3e, 0x4f, 0xd6, 0x11, 0x65, + 0x02, 0x5d, 0x09, 0x25, 0xf4, 0x29, 0xdd, 0x26, 0x02, 0xbb, 0x1e, 0xd7, 0x2b, 0xcf, 0x7e, 0x66, + 0xf3, 0xcb, 0x6f, 0xfd, 0xe3, 0x1b, 0x13, 0x0f, 0xc3, 0x83, 0x66, 0xcc, 0x69, 0xc6, 0x83, 0x40, + 0xbc, 0xf1, 0x79, 0xad, 0x04, 0xee, 0xee, 0xca, 0x12, 0x7c, 0x2c, 0x6f, 0x5e, 0x13, 0x20, 0x4e, + 0xe6, 0x17, 0x94, 0x3c, 0xbc, 0xaa, 0xb6, 0xaa, 0xcf, 0xa9, 0xda, 0xe9, 0x84, 0x87, 0x30, 0x85, + 0xdd, 0x14, 0x20, 0xb1, 0x82, 0x05, 0xb2, 0x58, 0x10, 0x44, 0x32, 0x36, 0x47, 0x82, 0x45, 0xc3, + 0xe4, 0x52, 0xb2, 0x83, 0x34, 0x1c, 0x8f, 0x69, 0xd8, 0x37, 0x87, 0x6d, 0x94, 0xec, 0xf7, 0x5e, + 0xc8, 0x62, 0xe0, 0x0b, 0x09, 0x03, 0xc7, 0xd2, 0x0c, 0x88, 0x75, 0x9f, 0xa0, 0xba, 0xcb, 0xeb, + 0xe1, 0x82, 0x30, 0x85, 0xa2, 0x5d, 0x1d, 0x11, 0x24, 0xa8, 0x24, 0xae, 0x4d, 0x25, 0x88, 0x70, + 0x11, 0x58, 0x8c, 0x36, 0xc3, 0x6d, 0x20, 0x27, 0x1f, 0x77, 0xa9, 0xa8, 0x84, 0xa3, 0xb9, 0x4b, + 0x1d, 0xf4, 0x68, 0x05, 0xb9, 0xb4, 0x89, 0x3d, 0xd7, 0x46, 0x7c, 0x9d, 0x0a, 0xbc, 0xd6, 0x43, + 0xc3, 0xf9, 0x1f, 0x4b, 0x6c, 0xbf, 0x3f, 0x10, 0xdb, 0xe7, 0xb2, 0x4c, 0xe6, 0x05, 0xb1, 0xed, + 0x49, 0xde, 0x31, 0x64, 0x33, 0xc2, 0xe9, 0x21, 0x81, 0xc8, 0x9a, 0xcb, 0xc5, 0x16, 0xc8, 0xfd, + 0x20, 0xfc, 0xc0, 0x08, 0x72, 0xcd, 0x0d, 0x19, 0x9f, 0x4d, 0xf8, 0xcb, 0x32, 0x38, 0x30, 0xec, + 0xf9, 0x0d, 0x2e, 0xe6, 0x25, 0x33, 0xfb, 0x01, 0x70, 0x1b, 0x84, 0xb7, 0x4a, 0xad, 0xea, 0xef, + 0x54, 0x6d, 0xfe, 0x9c, 0x40, 0xc1, 0x60, 0xc8, 0x3b, 0x7c, 0x87, 0x49, 0x4d, 0x13, 0xde, 0x79, + 0xe4, 0xdc, 0x21, 0xd2, 0x7f, 0x11, 0x91, 0x7e, 0x1c, 0xbe, 0xa2, 0x80, 0xbd, 0x4f, 0x31, 0x81, + 0xa2, 0x74, 0xeb, 0x37, 0xb2, 0xa0, 0x79, 0x5e, 0x49, 0xa8, 0x39, 0xb1, 0x2d, 0x6a, 0xe2, 0x75, + 0x3f, 0x8e, 0x8b, 0x4b, 0x51, 0xe4, 0x3d, 0x5a, 0x5b, 0xcb, 0xc3, 0xd2, 0xf9, 0x3f, 0x49, 0xee, + 0xff, 0x30, 0x90, 0xfb, 0x9f, 0x66, 0xb9, 0xf0, 0x1d, 0xa5, 0x20, 0xf8, 0x05, 0x93, 0x9a, 0xbb, + 0x3e, 0xe6, 0x61, 0x75, 0x54, 0x7d, 0xf4, 0x4c, 0x21, 0xeb, 0xa5, 0x73, 0x61, 0x13, 0xde, 0x28, + 0x83, 0x07, 0x06, 0x9e, 0x51, 0xc0, 0xf9, 0xfc, 0x45, 0xd3, 0x77, 0xc2, 0xb1, 0x8d, 0x8a, 0xf9, + 0x52, 0xa9, 0x55, 0x7d, 0xb5, 0x58, 0xc5, 0xc8, 0x03, 0x14, 0x84, 0x2d, 0x8b, 0x35, 0xe8, 0x4e, + 0xed, 0x14, 0x5e, 0x96, 0x15, 0xf3, 0x83, 0xae, 0x8a, 0xf9, 0x66, 0x16, 0x6e, 0xd7, 0x8a, 0x56, + 0x4c, 0x86, 0xb7, 0x08, 0xdb, 0x76, 0x40, 0x38, 0x0f, 0x2b, 0xc5, 0xe5, 0x11, 0x45, 0x51, 0x63, + 0x78, 0x87, 0x16, 0x4a, 0xaf, 0x77, 0x79, 0x0b, 0xe5, 0x34, 0x3c, 0x35, 0xaa, 0x50, 0x52, 0x47, + 0x70, 0xe6, 0x46, 0xea, 0xc7, 0x26, 0xfc, 0x7b, 0x09, 0xc0, 0xfe, 0xf3, 0x33, 0x78, 0x26, 0x77, + 0x65, 0xa4, 0x4e, 0xec, 0xb4, 0xd9, 0x82, 0xd2, 0xb2, 0x2e, 0xfe, 0xa8, 0xb6, 0xaa, 0x2d, 0x55, + 0x5b, 0x4c, 0xef, 0x95, 0xac, 0x46, 0x10, 0x10, 0x2a, 0x50, 0x74, 0x22, 0x17, 0x6e, 0xa3, 0x93, + 0x25, 0x66, 0xbc, 0x6d, 0xba, 0xb3, 0xb6, 0x4d, 0x33, 0xd0, 0xdc, 0xf2, 0xb6, 0xc9, 0x8c, 0x68, + 0x81, 0xff, 0x29, 0x81, 0xf7, 0xf4, 0x9d, 0xb0, 0xc1, 0xd3, 0x5b, 0x80, 0x74, 0xd0, 0x81, 0xa3, + 0x76, 0xa6, 0x98, 0xb0, 0x04, 0xfc, 0x9f, 0x6a, 0xab, 0xfa, 0x92, 0xaa, 0x7d, 0x3a, 0xfb, 0xe1, + 0x90, 0xaf, 0x62, 0x1f, 0xc9, 0x98, 0x72, 0xe4, 0xd2, 0x11, 0xfc, 0xff, 0xdf, 0x3d, 0x3b, 0x8e, + 0xb1, 0xff, 0x1f, 0x60, 0xff, 0x18, 0x3c, 0x91, 0x13, 0x7b, 0x33, 0x3e, 0xf8, 0xfd, 0x6e, 0x19, + 0xdc, 0xd3, 0x4b, 0x22, 0xac, 0x14, 0xc0, 0x37, 0x41, 0xff, 0x74, 0x21, 0x59, 0x49, 0xfe, 0xd7, + 0x4b, 0xad, 0xea, 0x6f, 0x54, 0xed, 0x13, 0xe9, 0xa5, 0x3d, 0xcd, 0xfb, 0xc0, 0xd5, 0xbc, 0x7d, + 0x6c, 0x96, 0x14, 0x44, 0xe8, 0xec, 0x21, 0xde, 0x5d, 0x17, 0x3b, 0xc3, 0xfc, 0x4b, 0x92, 0xf9, + 0xef, 0xf5, 0x30, 0x7f, 0x3d, 0x0b, 0xa0, 0x2f, 0xe6, 0x64, 0xbe, 0xed, 0xf7, 0x6d, 0xa1, 0xfe, + 0x75, 0x49, 0xfd, 0xaf, 0x07, 0x52, 0xff, 0xc3, 0x2c, 0xa3, 0xaf, 0x2b, 0x1b, 0x7a, 0xc0, 0x98, + 0xd0, 0x2b, 0x29, 0xfc, 0x53, 0x8a, 0xf3, 0xef, 0x8b, 0xea, 0xdc, 0x41, 0x8e, 0xdb, 0x24, 0x34, + 0x95, 0xd8, 0x99, 0xee, 0xa2, 0x40, 0x2c, 0x40, 0x36, 0xf1, 0x88, 0x20, 0x7d, 0x1b, 0xbb, 0xcd, + 0x2d, 0x3f, 0x21, 0x64, 0xd6, 0x84, 0xb9, 0xd1, 0x9e, 0x74, 0x13, 0x3e, 0x5f, 0x06, 0xfb, 0xb3, + 0x0e, 0xe1, 0xe1, 0xd9, 0x3c, 0x9c, 0xf7, 0xbf, 0x9c, 0xd0, 0x1e, 0x2f, 0x2c, 0x2f, 0x6b, 0xe5, + 0x5f, 0x6a, 0xab, 0xfa, 0xb2, 0xaa, 0x2d, 0x65, 0x77, 0x09, 0x79, 0x2c, 0x3e, 0x6e, 0x14, 0xe3, + 0x46, 0xd1, 0xd5, 0x28, 0x2a, 0xf0, 0x64, 0xde, 0xa2, 0x68, 0xbf, 0x1e, 0xfa, 0x49, 0x19, 0xdc, + 0x9b, 0x81, 0x24, 0x9c, 0x2d, 0x86, 0x72, 0x52, 0x09, 0x67, 0x8b, 0x8a, 0xcb, 0x42, 0xf8, 0x56, + 0xa9, 0x55, 0xfd, 0xbd, 0xaa, 0x5d, 0x4e, 0x37, 0x8d, 0x1e, 0xfc, 0xb7, 0xd7, 0x37, 0x8c, 0x71, + 0xe3, 0xb8, 0xa3, 0x1a, 0xc7, 0x22, 0x5c, 0x28, 0x5a, 0x23, 0x5d, 0xbd, 0xe3, 0x85, 0x32, 0xb8, + 0x2f, 0xf3, 0x65, 0x1d, 0xcc, 0xb5, 0xf8, 0x67, 0xbc, 0xc7, 0xd4, 0x3e, 0x54, 0x5c, 0x81, 0xac, + 0x9a, 0x7f, 0xab, 0xad, 0xea, 0x2b, 0xaa, 0xf6, 0xd9, 0xec, 0xf6, 0x91, 0xbc, 0x3a, 0x1b, 0xf7, + 0x8f, 0x71, 0xff, 0xc8, 0x7b, 0x9a, 0xd4, 0x5b, 0x1b, 0x9d, 0xf7, 0xc8, 0x3f, 0x4f, 0x6f, 0xa6, + 0x52, 0x54, 0xe6, 0xdb, 0x4c, 0xf5, 0xbf, 0x51, 0xd7, 0x1e, 0x2f, 0x2c, 0x2f, 0xab, 0xe1, 0xdb, + 0xa5, 0x56, 0xf5, 0x75, 0x55, 0x7b, 0x36, 0xdd, 0x43, 0x7a, 0x6b, 0x60, 0xdc, 0x44, 0xc6, 0x4d, + 0x64, 0xeb, 0x4d, 0xe4, 0x49, 0xf8, 0x44, 0xe1, 0x42, 0xe9, 0xea, 0x22, 0xbf, 0x9d, 0x00, 0xe5, + 0xf8, 0xbb, 0x37, 0x78, 0x64, 0x2b, 0x98, 0xa7, 0x3f, 0xbb, 0xd3, 0x66, 0x72, 0x48, 0xc8, 0x52, + 0x78, 0x4b, 0x69, 0x55, 0x7f, 0xa4, 0x68, 0x66, 0xbb, 0x31, 0x78, 0x5e, 0x27, 0xe7, 0x3c, 0x59, + 0xf2, 0x3b, 0x0b, 0x49, 0x9d, 0xd9, 0x0d, 0x8f, 0x18, 0xba, 0x00, 0x93, 0x83, 0xf0, 0x8e, 0x3f, + 0xd4, 0x83, 0xb5, 0x42, 0x3c, 0xaf, 0xa5, 0x6e, 0x70, 0x9f, 0x58, 0xe6, 0x91, 0x93, 0x4b, 0xb1, + 0x42, 0xa3, 0x6e, 0x47, 0xa1, 0xd6, 0x21, 0x1a, 0x12, 0xea, 0xf8, 0x93, 0xc1, 0x0b, 0x6f, 0xdc, + 0x9c, 0x54, 0xde, 0xbc, 0x39, 0xa9, 0xfc, 0xed, 0xe6, 0xa4, 0x72, 0xfd, 0xd6, 0xe4, 0xae, 0x37, + 0x6f, 0x4d, 0xee, 0xfa, 0xf3, 0xad, 0xc9, 0x5d, 0x97, 0x8f, 0xa5, 0xac, 0x71, 0x02, 0xdc, 0x74, + 0xc5, 0xfa, 0xb4, 0x4d, 0x9a, 0x69, 0x5d, 0x69, 0x13, 0xc2, 0x6a, 0xe0, 0xcb, 0xe5, 0xe8, 0x6b, + 0xde, 0x63, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x82, 0x5f, 0x48, 0x66, 0xc8, 0x2c, 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 { + // Get existing liquidity pools. + LiquidityPools(ctx context.Context, in *QueryLiquidityPoolsRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolsResponse, error) + // Get specific liquidity pool. + LiquidityPool(ctx context.Context, in *QueryLiquidityPoolRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolResponse, error) + // Get specific liquidity pool corresponding to the pool_coin_denom. + LiquidityPoolByPoolCoinDenom(ctx context.Context, in *QueryLiquidityPoolByPoolCoinDenomRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolResponse, error) + // Get specific liquidity pool corresponding to the reserve account. + LiquidityPoolByReserveAcc(ctx context.Context, in *QueryLiquidityPoolByReserveAccRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolResponse, error) + // Get the pool's current batch. + LiquidityPoolBatch(ctx context.Context, in *QueryLiquidityPoolBatchRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolBatchResponse, error) + // Get all swap messages in the pool's current batch. + PoolBatchSwapMsgs(ctx context.Context, in *QueryPoolBatchSwapMsgsRequest, opts ...grpc.CallOption) (*QueryPoolBatchSwapMsgsResponse, error) + // Get a specific swap message in the pool's current batch. + PoolBatchSwapMsg(ctx context.Context, in *QueryPoolBatchSwapMsgRequest, opts ...grpc.CallOption) (*QueryPoolBatchSwapMsgResponse, error) + // Get all deposit messages in the pool's current batch. + PoolBatchDepositMsgs(ctx context.Context, in *QueryPoolBatchDepositMsgsRequest, opts ...grpc.CallOption) (*QueryPoolBatchDepositMsgsResponse, error) + // Get a specific deposit message in the pool's current batch. + PoolBatchDepositMsg(ctx context.Context, in *QueryPoolBatchDepositMsgRequest, opts ...grpc.CallOption) (*QueryPoolBatchDepositMsgResponse, error) + // Get all withdraw messages in the pool's current batch. + PoolBatchWithdrawMsgs(ctx context.Context, in *QueryPoolBatchWithdrawMsgsRequest, opts ...grpc.CallOption) (*QueryPoolBatchWithdrawMsgsResponse, error) + // Get a specific withdraw message in the pool's current batch. + PoolBatchWithdrawMsg(ctx context.Context, in *QueryPoolBatchWithdrawMsgRequest, opts ...grpc.CallOption) (*QueryPoolBatchWithdrawMsgResponse, error) + // Get all parameters of the liquidity module. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) LiquidityPools(ctx context.Context, in *QueryLiquidityPoolsRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolsResponse, error) { + out := new(QueryLiquidityPoolsResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/LiquidityPools", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) LiquidityPool(ctx context.Context, in *QueryLiquidityPoolRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolResponse, error) { + out := new(QueryLiquidityPoolResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/LiquidityPool", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) LiquidityPoolByPoolCoinDenom(ctx context.Context, in *QueryLiquidityPoolByPoolCoinDenomRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolResponse, error) { + out := new(QueryLiquidityPoolResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/LiquidityPoolByPoolCoinDenom", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) LiquidityPoolByReserveAcc(ctx context.Context, in *QueryLiquidityPoolByReserveAccRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolResponse, error) { + out := new(QueryLiquidityPoolResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/LiquidityPoolByReserveAcc", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) LiquidityPoolBatch(ctx context.Context, in *QueryLiquidityPoolBatchRequest, opts ...grpc.CallOption) (*QueryLiquidityPoolBatchResponse, error) { + out := new(QueryLiquidityPoolBatchResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/LiquidityPoolBatch", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) PoolBatchSwapMsgs(ctx context.Context, in *QueryPoolBatchSwapMsgsRequest, opts ...grpc.CallOption) (*QueryPoolBatchSwapMsgsResponse, error) { + out := new(QueryPoolBatchSwapMsgsResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/PoolBatchSwapMsgs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) PoolBatchSwapMsg(ctx context.Context, in *QueryPoolBatchSwapMsgRequest, opts ...grpc.CallOption) (*QueryPoolBatchSwapMsgResponse, error) { + out := new(QueryPoolBatchSwapMsgResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/PoolBatchSwapMsg", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) PoolBatchDepositMsgs(ctx context.Context, in *QueryPoolBatchDepositMsgsRequest, opts ...grpc.CallOption) (*QueryPoolBatchDepositMsgsResponse, error) { + out := new(QueryPoolBatchDepositMsgsResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/PoolBatchDepositMsgs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) PoolBatchDepositMsg(ctx context.Context, in *QueryPoolBatchDepositMsgRequest, opts ...grpc.CallOption) (*QueryPoolBatchDepositMsgResponse, error) { + out := new(QueryPoolBatchDepositMsgResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/PoolBatchDepositMsg", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) PoolBatchWithdrawMsgs(ctx context.Context, in *QueryPoolBatchWithdrawMsgsRequest, opts ...grpc.CallOption) (*QueryPoolBatchWithdrawMsgsResponse, error) { + out := new(QueryPoolBatchWithdrawMsgsResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/PoolBatchWithdrawMsgs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) PoolBatchWithdrawMsg(ctx context.Context, in *QueryPoolBatchWithdrawMsgRequest, opts ...grpc.CallOption) (*QueryPoolBatchWithdrawMsgResponse, error) { + out := new(QueryPoolBatchWithdrawMsgResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/PoolBatchWithdrawMsg", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Get existing liquidity pools. + LiquidityPools(context.Context, *QueryLiquidityPoolsRequest) (*QueryLiquidityPoolsResponse, error) + // Get specific liquidity pool. + LiquidityPool(context.Context, *QueryLiquidityPoolRequest) (*QueryLiquidityPoolResponse, error) + // Get specific liquidity pool corresponding to the pool_coin_denom. + LiquidityPoolByPoolCoinDenom(context.Context, *QueryLiquidityPoolByPoolCoinDenomRequest) (*QueryLiquidityPoolResponse, error) + // Get specific liquidity pool corresponding to the reserve account. + LiquidityPoolByReserveAcc(context.Context, *QueryLiquidityPoolByReserveAccRequest) (*QueryLiquidityPoolResponse, error) + // Get the pool's current batch. + LiquidityPoolBatch(context.Context, *QueryLiquidityPoolBatchRequest) (*QueryLiquidityPoolBatchResponse, error) + // Get all swap messages in the pool's current batch. + PoolBatchSwapMsgs(context.Context, *QueryPoolBatchSwapMsgsRequest) (*QueryPoolBatchSwapMsgsResponse, error) + // Get a specific swap message in the pool's current batch. + PoolBatchSwapMsg(context.Context, *QueryPoolBatchSwapMsgRequest) (*QueryPoolBatchSwapMsgResponse, error) + // Get all deposit messages in the pool's current batch. + PoolBatchDepositMsgs(context.Context, *QueryPoolBatchDepositMsgsRequest) (*QueryPoolBatchDepositMsgsResponse, error) + // Get a specific deposit message in the pool's current batch. + PoolBatchDepositMsg(context.Context, *QueryPoolBatchDepositMsgRequest) (*QueryPoolBatchDepositMsgResponse, error) + // Get all withdraw messages in the pool's current batch. + PoolBatchWithdrawMsgs(context.Context, *QueryPoolBatchWithdrawMsgsRequest) (*QueryPoolBatchWithdrawMsgsResponse, error) + // Get a specific withdraw message in the pool's current batch. + PoolBatchWithdrawMsg(context.Context, *QueryPoolBatchWithdrawMsgRequest) (*QueryPoolBatchWithdrawMsgResponse, error) + // Get all parameters of the liquidity module. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) LiquidityPools(ctx context.Context, req *QueryLiquidityPoolsRequest) (*QueryLiquidityPoolsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method LiquidityPools not implemented") +} +func (*UnimplementedQueryServer) LiquidityPool(ctx context.Context, req *QueryLiquidityPoolRequest) (*QueryLiquidityPoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method LiquidityPool not implemented") +} +func (*UnimplementedQueryServer) LiquidityPoolByPoolCoinDenom(ctx context.Context, req *QueryLiquidityPoolByPoolCoinDenomRequest) (*QueryLiquidityPoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method LiquidityPoolByPoolCoinDenom not implemented") +} +func (*UnimplementedQueryServer) LiquidityPoolByReserveAcc(ctx context.Context, req *QueryLiquidityPoolByReserveAccRequest) (*QueryLiquidityPoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method LiquidityPoolByReserveAcc not implemented") +} +func (*UnimplementedQueryServer) LiquidityPoolBatch(ctx context.Context, req *QueryLiquidityPoolBatchRequest) (*QueryLiquidityPoolBatchResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method LiquidityPoolBatch not implemented") +} +func (*UnimplementedQueryServer) PoolBatchSwapMsgs(ctx context.Context, req *QueryPoolBatchSwapMsgsRequest) (*QueryPoolBatchSwapMsgsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PoolBatchSwapMsgs not implemented") +} +func (*UnimplementedQueryServer) PoolBatchSwapMsg(ctx context.Context, req *QueryPoolBatchSwapMsgRequest) (*QueryPoolBatchSwapMsgResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PoolBatchSwapMsg not implemented") +} +func (*UnimplementedQueryServer) PoolBatchDepositMsgs(ctx context.Context, req *QueryPoolBatchDepositMsgsRequest) (*QueryPoolBatchDepositMsgsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PoolBatchDepositMsgs not implemented") +} +func (*UnimplementedQueryServer) PoolBatchDepositMsg(ctx context.Context, req *QueryPoolBatchDepositMsgRequest) (*QueryPoolBatchDepositMsgResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PoolBatchDepositMsg not implemented") +} +func (*UnimplementedQueryServer) PoolBatchWithdrawMsgs(ctx context.Context, req *QueryPoolBatchWithdrawMsgsRequest) (*QueryPoolBatchWithdrawMsgsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PoolBatchWithdrawMsgs not implemented") +} +func (*UnimplementedQueryServer) PoolBatchWithdrawMsg(ctx context.Context, req *QueryPoolBatchWithdrawMsgRequest) (*QueryPoolBatchWithdrawMsgResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PoolBatchWithdrawMsg not implemented") +} +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_LiquidityPools_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryLiquidityPoolsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).LiquidityPools(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/LiquidityPools", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).LiquidityPools(ctx, req.(*QueryLiquidityPoolsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_LiquidityPool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryLiquidityPoolRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).LiquidityPool(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/LiquidityPool", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).LiquidityPool(ctx, req.(*QueryLiquidityPoolRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_LiquidityPoolByPoolCoinDenom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryLiquidityPoolByPoolCoinDenomRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).LiquidityPoolByPoolCoinDenom(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/LiquidityPoolByPoolCoinDenom", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).LiquidityPoolByPoolCoinDenom(ctx, req.(*QueryLiquidityPoolByPoolCoinDenomRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_LiquidityPoolByReserveAcc_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryLiquidityPoolByReserveAccRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).LiquidityPoolByReserveAcc(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/LiquidityPoolByReserveAcc", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).LiquidityPoolByReserveAcc(ctx, req.(*QueryLiquidityPoolByReserveAccRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_LiquidityPoolBatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryLiquidityPoolBatchRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).LiquidityPoolBatch(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/LiquidityPoolBatch", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).LiquidityPoolBatch(ctx, req.(*QueryLiquidityPoolBatchRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_PoolBatchSwapMsgs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPoolBatchSwapMsgsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).PoolBatchSwapMsgs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/PoolBatchSwapMsgs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).PoolBatchSwapMsgs(ctx, req.(*QueryPoolBatchSwapMsgsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_PoolBatchSwapMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPoolBatchSwapMsgRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).PoolBatchSwapMsg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/PoolBatchSwapMsg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).PoolBatchSwapMsg(ctx, req.(*QueryPoolBatchSwapMsgRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_PoolBatchDepositMsgs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPoolBatchDepositMsgsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).PoolBatchDepositMsgs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/PoolBatchDepositMsgs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).PoolBatchDepositMsgs(ctx, req.(*QueryPoolBatchDepositMsgsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_PoolBatchDepositMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPoolBatchDepositMsgRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).PoolBatchDepositMsg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/PoolBatchDepositMsg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).PoolBatchDepositMsg(ctx, req.(*QueryPoolBatchDepositMsgRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_PoolBatchWithdrawMsgs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPoolBatchWithdrawMsgsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).PoolBatchWithdrawMsgs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/PoolBatchWithdrawMsgs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).PoolBatchWithdrawMsgs(ctx, req.(*QueryPoolBatchWithdrawMsgsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_PoolBatchWithdrawMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPoolBatchWithdrawMsgRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).PoolBatchWithdrawMsg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Query/PoolBatchWithdrawMsg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).PoolBatchWithdrawMsg(ctx, req.(*QueryPoolBatchWithdrawMsgRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.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) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "tendermint.liquidity.v1beta1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "LiquidityPools", + Handler: _Query_LiquidityPools_Handler, + }, + { + MethodName: "LiquidityPool", + Handler: _Query_LiquidityPool_Handler, + }, + { + MethodName: "LiquidityPoolByPoolCoinDenom", + Handler: _Query_LiquidityPoolByPoolCoinDenom_Handler, + }, + { + MethodName: "LiquidityPoolByReserveAcc", + Handler: _Query_LiquidityPoolByReserveAcc_Handler, + }, + { + MethodName: "LiquidityPoolBatch", + Handler: _Query_LiquidityPoolBatch_Handler, + }, + { + MethodName: "PoolBatchSwapMsgs", + Handler: _Query_PoolBatchSwapMsgs_Handler, + }, + { + MethodName: "PoolBatchSwapMsg", + Handler: _Query_PoolBatchSwapMsg_Handler, + }, + { + MethodName: "PoolBatchDepositMsgs", + Handler: _Query_PoolBatchDepositMsgs_Handler, + }, + { + MethodName: "PoolBatchDepositMsg", + Handler: _Query_PoolBatchDepositMsg_Handler, + }, + { + MethodName: "PoolBatchWithdrawMsgs", + Handler: _Query_PoolBatchWithdrawMsgs_Handler, + }, + { + MethodName: "PoolBatchWithdrawMsg", + Handler: _Query_PoolBatchWithdrawMsg_Handler, + }, + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "tendermint/liquidity/v1beta1/query.proto", +} + +func (m *QueryLiquidityPoolRequest) 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 *QueryLiquidityPoolRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryLiquidityPoolRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryLiquidityPoolResponse) 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 *QueryLiquidityPoolResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryLiquidityPoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Pool.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 *QueryLiquidityPoolByPoolCoinDenomRequest) 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 *QueryLiquidityPoolByPoolCoinDenomRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryLiquidityPoolByPoolCoinDenomRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PoolCoinDenom) > 0 { + i -= len(m.PoolCoinDenom) + copy(dAtA[i:], m.PoolCoinDenom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.PoolCoinDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryLiquidityPoolByReserveAccRequest) 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 *QueryLiquidityPoolByReserveAccRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryLiquidityPoolByReserveAccRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ReserveAcc) > 0 { + i -= len(m.ReserveAcc) + copy(dAtA[i:], m.ReserveAcc) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ReserveAcc))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryLiquidityPoolBatchRequest) 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 *QueryLiquidityPoolBatchRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryLiquidityPoolBatchRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryLiquidityPoolBatchResponse) 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 *QueryLiquidityPoolBatchResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryLiquidityPoolBatchResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Batch.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 *QueryLiquidityPoolsRequest) 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 *QueryLiquidityPoolsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryLiquidityPoolsRequest) 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 *QueryLiquidityPoolsResponse) 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 *QueryLiquidityPoolsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryLiquidityPoolsResponse) 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.Pools) > 0 { + for iNdEx := len(m.Pools) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Pools[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 *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 *QueryPoolBatchSwapMsgsRequest) 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 *QueryPoolBatchSwapMsgsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchSwapMsgsRequest) 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 m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPoolBatchSwapMsgRequest) 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 *QueryPoolBatchSwapMsgRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchSwapMsgRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MsgIndex != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.MsgIndex)) + i-- + dAtA[i] = 0x10 + } + if m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPoolBatchSwapMsgsResponse) 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 *QueryPoolBatchSwapMsgsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchSwapMsgsResponse) 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.Swaps) > 0 { + for iNdEx := len(m.Swaps) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Swaps[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 *QueryPoolBatchSwapMsgResponse) 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 *QueryPoolBatchSwapMsgResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchSwapMsgResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Swap.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 *QueryPoolBatchDepositMsgsRequest) 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 *QueryPoolBatchDepositMsgsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchDepositMsgsRequest) 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 m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPoolBatchDepositMsgRequest) 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 *QueryPoolBatchDepositMsgRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchDepositMsgRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MsgIndex != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.MsgIndex)) + i-- + dAtA[i] = 0x10 + } + if m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPoolBatchDepositMsgsResponse) 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 *QueryPoolBatchDepositMsgsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchDepositMsgsResponse) 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.Deposits) > 0 { + for iNdEx := len(m.Deposits) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Deposits[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 *QueryPoolBatchDepositMsgResponse) 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 *QueryPoolBatchDepositMsgResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchDepositMsgResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Deposit.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 *QueryPoolBatchWithdrawMsgsRequest) 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 *QueryPoolBatchWithdrawMsgsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchWithdrawMsgsRequest) 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 m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPoolBatchWithdrawMsgRequest) 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 *QueryPoolBatchWithdrawMsgRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchWithdrawMsgRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MsgIndex != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.MsgIndex)) + i-- + dAtA[i] = 0x10 + } + if m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPoolBatchWithdrawMsgsResponse) 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 *QueryPoolBatchWithdrawMsgsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchWithdrawMsgsResponse) 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.Withdraws) > 0 { + for iNdEx := len(m.Withdraws) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Withdraws[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 *QueryPoolBatchWithdrawMsgResponse) 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 *QueryPoolBatchWithdrawMsgResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPoolBatchWithdrawMsgResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Withdraw.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 *QueryLiquidityPoolRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + return n +} + +func (m *QueryLiquidityPoolResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Pool.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryLiquidityPoolByPoolCoinDenomRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PoolCoinDenom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryLiquidityPoolByReserveAccRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ReserveAcc) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryLiquidityPoolBatchRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + return n +} + +func (m *QueryLiquidityPoolBatchResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Batch.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryLiquidityPoolsRequest) 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 *QueryLiquidityPoolsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Pools) > 0 { + for _, e := range m.Pools { + 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 *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 *QueryPoolBatchSwapMsgsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPoolBatchSwapMsgRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + if m.MsgIndex != 0 { + n += 1 + sovQuery(uint64(m.MsgIndex)) + } + return n +} + +func (m *QueryPoolBatchSwapMsgsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Swaps) > 0 { + for _, e := range m.Swaps { + 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 *QueryPoolBatchSwapMsgResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Swap.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryPoolBatchDepositMsgsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPoolBatchDepositMsgRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + if m.MsgIndex != 0 { + n += 1 + sovQuery(uint64(m.MsgIndex)) + } + return n +} + +func (m *QueryPoolBatchDepositMsgsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Deposits) > 0 { + for _, e := range m.Deposits { + 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 *QueryPoolBatchDepositMsgResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Deposit.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryPoolBatchWithdrawMsgsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPoolBatchWithdrawMsgRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + if m.MsgIndex != 0 { + n += 1 + sovQuery(uint64(m.MsgIndex)) + } + return n +} + +func (m *QueryPoolBatchWithdrawMsgsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Withdraws) > 0 { + for _, e := range m.Withdraws { + 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 *QueryPoolBatchWithdrawMsgResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Withdraw.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 *QueryLiquidityPoolRequest) 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: QueryLiquidityPoolRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryLiquidityPoolRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *QueryLiquidityPoolResponse) 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: QueryLiquidityPoolResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryLiquidityPoolResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pool", 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.Pool.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 *QueryLiquidityPoolByPoolCoinDenomRequest) 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: QueryLiquidityPoolByPoolCoinDenomRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryLiquidityPoolByPoolCoinDenomRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolCoinDenom", 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.PoolCoinDenom = 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 *QueryLiquidityPoolByReserveAccRequest) 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: QueryLiquidityPoolByReserveAccRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryLiquidityPoolByReserveAccRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReserveAcc", 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.ReserveAcc = 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 *QueryLiquidityPoolBatchRequest) 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: QueryLiquidityPoolBatchRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryLiquidityPoolBatchRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *QueryLiquidityPoolBatchResponse) 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: QueryLiquidityPoolBatchResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryLiquidityPoolBatchResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Batch", 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.Batch.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 *QueryLiquidityPoolsRequest) 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: QueryLiquidityPoolsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryLiquidityPoolsRequest: 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 *QueryLiquidityPoolsResponse) 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: QueryLiquidityPoolsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryLiquidityPoolsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pools", 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.Pools = append(m.Pools, Pool{}) + if err := m.Pools[len(m.Pools)-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 *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 *QueryPoolBatchSwapMsgsRequest) 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: QueryPoolBatchSwapMsgsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchSwapMsgsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *QueryPoolBatchSwapMsgRequest) 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: QueryPoolBatchSwapMsgRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchSwapMsgRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgIndex", wireType) + } + m.MsgIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MsgIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *QueryPoolBatchSwapMsgsResponse) 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: QueryPoolBatchSwapMsgsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchSwapMsgsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Swaps", 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.Swaps = append(m.Swaps, SwapMsgState{}) + if err := m.Swaps[len(m.Swaps)-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 *QueryPoolBatchSwapMsgResponse) 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: QueryPoolBatchSwapMsgResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchSwapMsgResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Swap", 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.Swap.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 *QueryPoolBatchDepositMsgsRequest) 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: QueryPoolBatchDepositMsgsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchDepositMsgsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *QueryPoolBatchDepositMsgRequest) 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: QueryPoolBatchDepositMsgRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchDepositMsgRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgIndex", wireType) + } + m.MsgIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MsgIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *QueryPoolBatchDepositMsgsResponse) 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: QueryPoolBatchDepositMsgsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchDepositMsgsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Deposits", 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.Deposits = append(m.Deposits, DepositMsgState{}) + if err := m.Deposits[len(m.Deposits)-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 *QueryPoolBatchDepositMsgResponse) 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: QueryPoolBatchDepositMsgResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchDepositMsgResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Deposit", 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.Deposit.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 *QueryPoolBatchWithdrawMsgsRequest) 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: QueryPoolBatchWithdrawMsgsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchWithdrawMsgsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *QueryPoolBatchWithdrawMsgRequest) 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: QueryPoolBatchWithdrawMsgRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchWithdrawMsgRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgIndex", wireType) + } + m.MsgIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MsgIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *QueryPoolBatchWithdrawMsgsResponse) 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: QueryPoolBatchWithdrawMsgsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchWithdrawMsgsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Withdraws", 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.Withdraws = append(m.Withdraws, WithdrawMsgState{}) + if err := m.Withdraws[len(m.Withdraws)-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 *QueryPoolBatchWithdrawMsgResponse) 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: QueryPoolBatchWithdrawMsgResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPoolBatchWithdrawMsgResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Withdraw", 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.Withdraw.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/liquidity/types/query.pb.gw.go b/x/liquidity/types/query.pb.gw.go new file mode 100644 index 00000000000..f1b68124340 --- /dev/null +++ b/x/liquidity/types/query.pb.gw.go @@ -0,0 +1,1366 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: tendermint/liquidity/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 + +var ( + filter_Query_LiquidityPools_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_LiquidityPools_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolsRequest + 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_LiquidityPools_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.LiquidityPools(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_LiquidityPools_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolsRequest + 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_LiquidityPools_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.LiquidityPools(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_LiquidityPool_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + msg, err := client.LiquidityPool(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_LiquidityPool_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + msg, err := server.LiquidityPool(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_LiquidityPoolByPoolCoinDenom_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolByPoolCoinDenomRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_coin_denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_coin_denom") + } + + protoReq.PoolCoinDenom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_coin_denom", err) + } + + msg, err := client.LiquidityPoolByPoolCoinDenom(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_LiquidityPoolByPoolCoinDenom_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolByPoolCoinDenomRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_coin_denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_coin_denom") + } + + protoReq.PoolCoinDenom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_coin_denom", err) + } + + msg, err := server.LiquidityPoolByPoolCoinDenom(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_LiquidityPoolByReserveAcc_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolByReserveAccRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["reserve_acc"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "reserve_acc") + } + + protoReq.ReserveAcc, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "reserve_acc", err) + } + + msg, err := client.LiquidityPoolByReserveAcc(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_LiquidityPoolByReserveAcc_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolByReserveAccRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["reserve_acc"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "reserve_acc") + } + + protoReq.ReserveAcc, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "reserve_acc", err) + } + + msg, err := server.LiquidityPoolByReserveAcc(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_LiquidityPoolBatch_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolBatchRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + msg, err := client.LiquidityPoolBatch(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_LiquidityPoolBatch_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryLiquidityPoolBatchRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + msg, err := server.LiquidityPoolBatch(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_PoolBatchSwapMsgs_0 = &utilities.DoubleArray{Encoding: map[string]int{"pool_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_PoolBatchSwapMsgs_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchSwapMsgsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", 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_PoolBatchSwapMsgs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.PoolBatchSwapMsgs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_PoolBatchSwapMsgs_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchSwapMsgsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", 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_PoolBatchSwapMsgs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.PoolBatchSwapMsgs(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_PoolBatchSwapMsg_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchSwapMsgRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + val, ok = pathParams["msg_index"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "msg_index") + } + + protoReq.MsgIndex, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "msg_index", err) + } + + msg, err := client.PoolBatchSwapMsg(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_PoolBatchSwapMsg_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchSwapMsgRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + val, ok = pathParams["msg_index"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "msg_index") + } + + protoReq.MsgIndex, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "msg_index", err) + } + + msg, err := server.PoolBatchSwapMsg(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_PoolBatchDepositMsgs_0 = &utilities.DoubleArray{Encoding: map[string]int{"pool_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_PoolBatchDepositMsgs_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchDepositMsgsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", 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_PoolBatchDepositMsgs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.PoolBatchDepositMsgs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_PoolBatchDepositMsgs_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchDepositMsgsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", 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_PoolBatchDepositMsgs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.PoolBatchDepositMsgs(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_PoolBatchDepositMsg_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchDepositMsgRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + val, ok = pathParams["msg_index"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "msg_index") + } + + protoReq.MsgIndex, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "msg_index", err) + } + + msg, err := client.PoolBatchDepositMsg(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_PoolBatchDepositMsg_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchDepositMsgRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + val, ok = pathParams["msg_index"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "msg_index") + } + + protoReq.MsgIndex, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "msg_index", err) + } + + msg, err := server.PoolBatchDepositMsg(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_PoolBatchWithdrawMsgs_0 = &utilities.DoubleArray{Encoding: map[string]int{"pool_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_PoolBatchWithdrawMsgs_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchWithdrawMsgsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", 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_PoolBatchWithdrawMsgs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.PoolBatchWithdrawMsgs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_PoolBatchWithdrawMsgs_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchWithdrawMsgsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", 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_PoolBatchWithdrawMsgs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.PoolBatchWithdrawMsgs(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_PoolBatchWithdrawMsg_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchWithdrawMsgRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + val, ok = pathParams["msg_index"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "msg_index") + } + + protoReq.MsgIndex, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "msg_index", err) + } + + msg, err := client.PoolBatchWithdrawMsg(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_PoolBatchWithdrawMsg_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPoolBatchWithdrawMsgRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["pool_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pool_id") + } + + protoReq.PoolId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pool_id", err) + } + + val, ok = pathParams["msg_index"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "msg_index") + } + + protoReq.MsgIndex, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "msg_index", err) + } + + msg, err := server.PoolBatchWithdrawMsg(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_LiquidityPools_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_LiquidityPools_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_LiquidityPools_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_LiquidityPool_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_LiquidityPool_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_LiquidityPool_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_LiquidityPoolByPoolCoinDenom_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_LiquidityPoolByPoolCoinDenom_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_LiquidityPoolByPoolCoinDenom_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_LiquidityPoolByReserveAcc_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_LiquidityPoolByReserveAcc_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_LiquidityPoolByReserveAcc_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_LiquidityPoolBatch_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_LiquidityPoolBatch_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_LiquidityPoolBatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchSwapMsgs_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_PoolBatchSwapMsgs_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_PoolBatchSwapMsgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchSwapMsg_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_PoolBatchSwapMsg_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_PoolBatchSwapMsg_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchDepositMsgs_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_PoolBatchDepositMsgs_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_PoolBatchDepositMsgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchDepositMsg_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_PoolBatchDepositMsg_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_PoolBatchDepositMsg_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchWithdrawMsgs_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_PoolBatchWithdrawMsgs_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_PoolBatchWithdrawMsgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchWithdrawMsg_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_PoolBatchWithdrawMsg_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_PoolBatchWithdrawMsg_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_LiquidityPools_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_LiquidityPools_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_LiquidityPools_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_LiquidityPool_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_LiquidityPool_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_LiquidityPool_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_LiquidityPoolByPoolCoinDenom_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_LiquidityPoolByPoolCoinDenom_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_LiquidityPoolByPoolCoinDenom_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_LiquidityPoolByReserveAcc_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_LiquidityPoolByReserveAcc_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_LiquidityPoolByReserveAcc_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_LiquidityPoolBatch_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_LiquidityPoolBatch_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_LiquidityPoolBatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchSwapMsgs_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_PoolBatchSwapMsgs_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_PoolBatchSwapMsgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchSwapMsg_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_PoolBatchSwapMsg_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_PoolBatchSwapMsg_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchDepositMsgs_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_PoolBatchDepositMsgs_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_PoolBatchDepositMsgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchDepositMsg_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_PoolBatchDepositMsg_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_PoolBatchDepositMsg_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchWithdrawMsgs_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_PoolBatchWithdrawMsgs_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_PoolBatchWithdrawMsgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PoolBatchWithdrawMsg_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_PoolBatchWithdrawMsg_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_PoolBatchWithdrawMsg_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_LiquidityPools_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "liquidity", "v1beta1", "pools"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_LiquidityPool_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "liquidity", "v1beta1", "pools", "pool_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_LiquidityPoolByPoolCoinDenom_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "liquidity", "v1beta1", "pools", "pool_coin_denom"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_LiquidityPoolByReserveAcc_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "liquidity", "v1beta1", "pools", "reserve_acc"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_LiquidityPoolBatch_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"cosmos", "liquidity", "v1beta1", "pools", "pool_id", "batch"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_PoolBatchSwapMsgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 2, 6}, []string{"cosmos", "liquidity", "v1beta1", "pools", "pool_id", "batch", "swaps"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_PoolBatchSwapMsg_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"cosmos", "liquidity", "v1beta1", "pools", "pool_id", "batch", "swaps", "msg_index"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_PoolBatchDepositMsgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 2, 6}, []string{"cosmos", "liquidity", "v1beta1", "pools", "pool_id", "batch", "deposits"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_PoolBatchDepositMsg_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"cosmos", "liquidity", "v1beta1", "pools", "pool_id", "batch", "deposits", "msg_index"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_PoolBatchWithdrawMsgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 2, 6}, []string{"cosmos", "liquidity", "v1beta1", "pools", "pool_id", "batch", "withdraws"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_PoolBatchWithdrawMsg_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"cosmos", "liquidity", "v1beta1", "pools", "pool_id", "batch", "withdraws", "msg_index"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "liquidity", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_LiquidityPools_0 = runtime.ForwardResponseMessage + + forward_Query_LiquidityPool_0 = runtime.ForwardResponseMessage + + forward_Query_LiquidityPoolByPoolCoinDenom_0 = runtime.ForwardResponseMessage + + forward_Query_LiquidityPoolByReserveAcc_0 = runtime.ForwardResponseMessage + + forward_Query_LiquidityPoolBatch_0 = runtime.ForwardResponseMessage + + forward_Query_PoolBatchSwapMsgs_0 = runtime.ForwardResponseMessage + + forward_Query_PoolBatchSwapMsg_0 = runtime.ForwardResponseMessage + + forward_Query_PoolBatchDepositMsgs_0 = runtime.ForwardResponseMessage + + forward_Query_PoolBatchDepositMsg_0 = runtime.ForwardResponseMessage + + forward_Query_PoolBatchWithdrawMsgs_0 = runtime.ForwardResponseMessage + + forward_Query_PoolBatchWithdrawMsg_0 = runtime.ForwardResponseMessage + + forward_Query_Params_0 = runtime.ForwardResponseMessage +) diff --git a/x/liquidity/types/swap.go b/x/liquidity/types/swap.go new file mode 100644 index 00000000000..ccd46320b18 --- /dev/null +++ b/x/liquidity/types/swap.go @@ -0,0 +1,617 @@ +package types + +import ( + "sort" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Type of match +type MatchType int + +const ( + ExactMatch MatchType = iota + 1 + NoMatch + FractionalMatch +) + +// Direction of price +type PriceDirection int + +const ( + Increasing PriceDirection = iota + 1 + Decreasing + Staying +) + +// Direction of order +type OrderDirection int + +const ( + DirectionXtoY OrderDirection = iota + 1 + DirectionYtoX +) + +// Type of order map to index at price, having the pointer list of the swap batch message. +type Order struct { + Price sdk.Dec + BuyOfferAmt sdk.Int + SellOfferAmt sdk.Int + SwapMsgStates []*SwapMsgState +} + +// OrderBook is a list of orders +type OrderBook []Order + +// Len implements sort.Interface for OrderBook +func (orderBook OrderBook) Len() int { return len(orderBook) } + +// Less implements sort.Interface for OrderBook +func (orderBook OrderBook) Less(i, j int) bool { + return orderBook[i].Price.LT(orderBook[j].Price) +} + +// Swap implements sort.Interface for OrderBook +func (orderBook OrderBook) Swap(i, j int) { orderBook[i], orderBook[j] = orderBook[j], orderBook[i] } + +// increasing sort orderbook by order price +func (orderBook OrderBook) Sort() { + sort.Slice(orderBook, func(i, j int) bool { + return orderBook[i].Price.LT(orderBook[j].Price) + }) +} + +// decreasing sort orderbook by order price +func (orderBook OrderBook) Reverse() { + sort.Slice(orderBook, func(i, j int) bool { + return orderBook[i].Price.GT(orderBook[j].Price) + }) +} + +// Get number of not matched messages on the list. +func CountNotMatchedMsgs(swapMsgStates []*SwapMsgState) int { + cnt := 0 + for _, m := range swapMsgStates { + if m.Executed && !m.Succeeded { + cnt++ + } + } + return cnt +} + +// Get number of fractional matched messages on the list. +func CountFractionalMatchedMsgs(swapMsgStates []*SwapMsgState) int { + cnt := 0 + for _, m := range swapMsgStates { + if m.Executed && m.Succeeded && !m.ToBeDeleted { + cnt++ + } + } + return cnt +} + +// Order map type indexed by order price at price +type OrderMap map[string]Order + +// Make orderbook by sort orderMap. +func (orderMap OrderMap) SortOrderBook() (orderBook OrderBook) { + for _, o := range orderMap { + orderBook = append(orderBook, o) + } + orderBook.Sort() + return orderBook +} + +// struct of swap matching result of the batch +type BatchResult struct { + MatchType MatchType + PriceDirection PriceDirection + SwapPrice sdk.Dec + EX sdk.Dec + EY sdk.Dec + OriginalEX sdk.Int + OriginalEY sdk.Int + PoolX sdk.Dec + PoolY sdk.Dec + TransactAmt sdk.Dec +} + +// return of zero object, to avoid nil +func NewBatchResult() BatchResult { + return BatchResult{ + SwapPrice: sdk.ZeroDec(), + EX: sdk.ZeroDec(), + EY: sdk.ZeroDec(), + OriginalEX: sdk.ZeroInt(), + OriginalEY: sdk.ZeroInt(), + PoolX: sdk.ZeroDec(), + PoolY: sdk.ZeroDec(), + TransactAmt: sdk.ZeroDec(), + } +} + +// struct of swap matching result of each Batch swap message +type MatchResult struct { + OrderDirection OrderDirection + OrderMsgIndex uint64 + OrderPrice sdk.Dec + OfferCoinAmt sdk.Dec + TransactedCoinAmt sdk.Dec + ExchangedDemandCoinAmt sdk.Dec + OfferCoinFeeAmt sdk.Dec + ExchangedCoinFeeAmt sdk.Dec + SwapMsgState *SwapMsgState +} + +// The price and coins of swap messages in orderbook are calculated +// to derive match result with the price direction. +func (orderBook OrderBook) Match(x, y sdk.Dec) (BatchResult, bool) { + currentPrice := x.Quo(y) + priceDirection := orderBook.PriceDirection(currentPrice) + if priceDirection == Staying { + return orderBook.CalculateMatchStay(currentPrice), true + } + return orderBook.CalculateMatch(priceDirection, x, y) +} + +// Check orderbook validity naively +func (orderBook OrderBook) Validate(currentPrice sdk.Dec) bool { + if !currentPrice.IsPositive() { + return false + } + maxBuyOrderPrice := sdk.ZeroDec() + minSellOrderPrice := sdk.NewDec(1000000000000) + for _, order := range orderBook { + if order.BuyOfferAmt.IsPositive() && order.Price.GT(maxBuyOrderPrice) { + maxBuyOrderPrice = order.Price + } + if order.SellOfferAmt.IsPositive() && (order.Price.LT(minSellOrderPrice)) { + minSellOrderPrice = order.Price + } + } + if maxBuyOrderPrice.GT(minSellOrderPrice) || + maxBuyOrderPrice.Quo(currentPrice).GT(sdk.MustNewDecFromStr("1.10")) || + minSellOrderPrice.Quo(currentPrice).LT(sdk.MustNewDecFromStr("0.90")) { + return false + } + return true +} + +// Calculate results for orderbook matching with unchanged price case +func (orderBook OrderBook) CalculateMatchStay(currentPrice sdk.Dec) (r BatchResult) { + r = NewBatchResult() + r.SwapPrice = currentPrice + r.OriginalEX, r.OriginalEY = orderBook.ExecutableAmt(r.SwapPrice) + r.EX = r.OriginalEX.ToDec() + r.EY = r.OriginalEY.ToDec() + r.PriceDirection = Staying + + s := r.SwapPrice.Mul(r.EY) + if r.EX.IsZero() || r.EY.IsZero() { + r.MatchType = NoMatch + } else if r.EX.Equal(s) { // Normalization to an integrator for easy determination of exactMatch + r.MatchType = ExactMatch + } else { + // Decimal Error, When calculating the Executable value, conservatively Truncated decimal + r.MatchType = FractionalMatch + if r.EX.GT(s) { + r.EX = s + } else if r.EX.LT(s) { + r.EY = r.EX.Quo(r.SwapPrice) + } + } + return +} + +// Calculates the batch results with the logic for each direction +func (orderBook OrderBook) CalculateMatch(direction PriceDirection, x, y sdk.Dec) (maxScenario BatchResult, found bool) { + currentPrice := x.Quo(y) + lastOrderPrice := currentPrice + var matchScenarios []BatchResult + start, end, delta := 0, len(orderBook)-1, 1 + if direction == Decreasing { + start, end, delta = end, start, -1 + } + for i := start; i != end+delta; i += delta { + order := orderBook[i] + if (direction == Increasing && order.Price.LT(currentPrice)) || + (direction == Decreasing && order.Price.GT(currentPrice)) { + continue + } else { + orderPrice := order.Price + r := orderBook.CalculateSwap(direction, x, y, orderPrice, lastOrderPrice) + // Check to see if it exceeds a value that can be a decimal error + if (direction == Increasing && r.PoolY.Sub(r.EX.Quo(r.SwapPrice)).GTE(sdk.OneDec())) || + (direction == Decreasing && r.PoolX.Sub(r.EY.Mul(r.SwapPrice)).GTE(sdk.OneDec())) { + continue + } + matchScenarios = append(matchScenarios, r) + lastOrderPrice = orderPrice + } + } + maxScenario = NewBatchResult() + for _, s := range matchScenarios { + MEX, MEY := orderBook.MustExecutableAmt(s.SwapPrice) + if s.EX.GTE(MEX.ToDec()) && s.EY.GTE(MEY.ToDec()) { + if s.MatchType == ExactMatch && s.TransactAmt.IsPositive() { + maxScenario = s + found = true + break + } else if s.TransactAmt.GT(maxScenario.TransactAmt) { + maxScenario = s + found = true + } + } + } + maxScenario.PriceDirection = direction + return maxScenario, found +} + +// CalculateSwap calculates the batch result. +func (orderBook OrderBook) CalculateSwap(direction PriceDirection, x, y, orderPrice, lastOrderPrice sdk.Dec) BatchResult { + r := NewBatchResult() + r.OriginalEX, r.OriginalEY = orderBook.ExecutableAmt(lastOrderPrice.Add(orderPrice).Quo(sdk.NewDec(2))) + r.EX = r.OriginalEX.ToDec() + r.EY = r.OriginalEY.ToDec() + + r.SwapPrice = x.Add(r.EX.MulInt64(2)).Quo(y.Add(r.EY.MulInt64(2))) // P_s = (X + 2EX) / (Y + 2EY) + + if direction == Increasing { + r.PoolY = r.SwapPrice.Mul(y).Sub(x).Quo(r.SwapPrice.MulInt64(2)) // (P_s * Y - X / 2P_s) + if lastOrderPrice.LT(r.SwapPrice) && r.SwapPrice.LT(orderPrice) && !r.PoolY.IsNegative() { + if r.EX.IsZero() && r.EY.IsZero() { + r.MatchType = NoMatch + } else { + r.MatchType = ExactMatch + } + } + } else if direction == Decreasing { + r.PoolX = x.Sub(r.SwapPrice.Mul(y)).QuoInt64(2) // (X - P_s * Y) / 2 + if orderPrice.LT(r.SwapPrice) && r.SwapPrice.LT(lastOrderPrice) && !r.PoolX.IsNegative() { + if r.EX.IsZero() && r.EY.IsZero() { + r.MatchType = NoMatch + } else { + r.MatchType = ExactMatch + } + } + } + + if r.MatchType == 0 { + r.OriginalEX, r.OriginalEY = orderBook.ExecutableAmt(orderPrice) + r.EX = r.OriginalEX.ToDec() + r.EY = r.OriginalEY.ToDec() + r.SwapPrice = orderPrice + // When calculating the Pool value, conservatively Truncated decimal, so Ceil it to reduce the decimal error + if direction == Increasing { + r.PoolY = r.SwapPrice.Mul(y).Sub(x).Quo(r.SwapPrice.MulInt64(2)) // (P_s * Y - X) / 2P_s + r.EX = sdk.MinDec(r.EX, r.EY.Add(r.PoolY).Mul(r.SwapPrice)).Ceil() + r.EY = sdk.MaxDec(sdk.MinDec(r.EY, r.EX.Quo(r.SwapPrice).Sub(r.PoolY)), sdk.ZeroDec()).Ceil() + } else if direction == Decreasing { + r.PoolX = x.Sub(r.SwapPrice.Mul(y)).QuoInt64(2) // (X - P_s * Y) / 2 + r.EY = sdk.MinDec(r.EY, r.EX.Add(r.PoolX).Quo(r.SwapPrice)).Ceil() + r.EX = sdk.MaxDec(sdk.MinDec(r.EX, r.EY.Mul(r.SwapPrice).Sub(r.PoolX)), sdk.ZeroDec()).Ceil() + } + r.MatchType = FractionalMatch + } + + if direction == Increasing { + if r.SwapPrice.LT(x.Quo(y)) || r.PoolY.IsNegative() { + r.TransactAmt = sdk.ZeroDec() + } else { + r.TransactAmt = sdk.MinDec(r.EX, r.EY.Add(r.PoolY).Mul(r.SwapPrice)) + } + } else if direction == Decreasing { + if r.SwapPrice.GT(x.Quo(y)) || r.PoolX.IsNegative() { + r.TransactAmt = sdk.ZeroDec() + } else { + r.TransactAmt = sdk.MinDec(r.EY, r.EX.Add(r.PoolX).Quo(r.SwapPrice)) + } + } + return r +} + +// Get Price direction of the orderbook with current Price +func (orderBook OrderBook) PriceDirection(currentPrice sdk.Dec) PriceDirection { + buyAmtOverCurrentPrice := sdk.ZeroDec() + buyAmtAtCurrentPrice := sdk.ZeroDec() + sellAmtUnderCurrentPrice := sdk.ZeroDec() + sellAmtAtCurrentPrice := sdk.ZeroDec() + + for _, order := range orderBook { + if order.Price.GT(currentPrice) { + buyAmtOverCurrentPrice = buyAmtOverCurrentPrice.Add(order.BuyOfferAmt.ToDec()) + } else if order.Price.Equal(currentPrice) { + buyAmtAtCurrentPrice = buyAmtAtCurrentPrice.Add(order.BuyOfferAmt.ToDec()) + sellAmtAtCurrentPrice = sellAmtAtCurrentPrice.Add(order.SellOfferAmt.ToDec()) + } else if order.Price.LT(currentPrice) { + sellAmtUnderCurrentPrice = sellAmtUnderCurrentPrice.Add(order.SellOfferAmt.ToDec()) + } + } + if buyAmtOverCurrentPrice.GT(currentPrice.Mul(sellAmtUnderCurrentPrice.Add(sellAmtAtCurrentPrice))) { + return Increasing + } else if currentPrice.Mul(sellAmtUnderCurrentPrice).GT(buyAmtOverCurrentPrice.Add(buyAmtAtCurrentPrice)) { + return Decreasing + } + return Staying +} + +// calculate the executable amount of the orderbook for each X, Y +func (orderBook OrderBook) ExecutableAmt(swapPrice sdk.Dec) (executableBuyAmtX, executableSellAmtY sdk.Int) { + executableBuyAmtX = sdk.ZeroInt() + executableSellAmtY = sdk.ZeroInt() + for _, order := range orderBook { + if order.Price.GTE(swapPrice) { + executableBuyAmtX = executableBuyAmtX.Add(order.BuyOfferAmt) + } + if order.Price.LTE(swapPrice) { + executableSellAmtY = executableSellAmtY.Add(order.SellOfferAmt) + } + } + return +} + +// Check swap executable amount validity of the orderbook +func (orderBook OrderBook) MustExecutableAmt(swapPrice sdk.Dec) (mustExecutableBuyAmtX, mustExecutableSellAmtY sdk.Int) { + mustExecutableBuyAmtX = sdk.ZeroInt() + mustExecutableSellAmtY = sdk.ZeroInt() + for _, order := range orderBook { + if order.Price.GT(swapPrice) { + mustExecutableBuyAmtX = mustExecutableBuyAmtX.Add(order.BuyOfferAmt) + } + if order.Price.LT(swapPrice) { + mustExecutableSellAmtY = mustExecutableSellAmtY.Add(order.SellOfferAmt) + } + } + return +} + +// make orderMap key as swap price, value as Buy, Sell Amount from swap msgs, with split as Buy xToY, Sell yToX msg list. +func MakeOrderMap(swapMsgs []*SwapMsgState, denomX, denomY string, onlyNotMatched bool) (OrderMap, []*SwapMsgState, []*SwapMsgState) { + orderMap := make(OrderMap) + var xToY []*SwapMsgState // buying Y from X + var yToX []*SwapMsgState // selling Y for X + for _, m := range swapMsgs { + if onlyNotMatched && (m.ToBeDeleted || m.RemainingOfferCoin.IsZero()) { + continue + } + order := Order{ + Price: m.Msg.OrderPrice, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.ZeroInt(), + } + orderPriceString := m.Msg.OrderPrice.String() + switch { + // buying Y from X + case m.Msg.OfferCoin.Denom == denomX: + xToY = append(xToY, m) + if o, ok := orderMap[orderPriceString]; ok { + order = o + order.BuyOfferAmt = o.BuyOfferAmt.Add(m.RemainingOfferCoin.Amount) + } else { + order.BuyOfferAmt = m.RemainingOfferCoin.Amount + } + // selling Y for X + case m.Msg.OfferCoin.Denom == denomY: + yToX = append(yToX, m) + if o, ok := orderMap[orderPriceString]; ok { + order = o + order.SellOfferAmt = o.SellOfferAmt.Add(m.RemainingOfferCoin.Amount) + } else { + order.SellOfferAmt = m.RemainingOfferCoin.Amount + } + default: + panic(ErrInvalidDenom) + } + order.SwapMsgStates = append(order.SwapMsgStates, m) + orderMap[orderPriceString] = order + } + return orderMap, xToY, yToX +} + +// check validity state of the batch swap messages, and set to delete state to height timeout expired order +func ValidateStateAndExpireOrders(swapMsgStates []*SwapMsgState, currentHeight int64, expireThisHeight bool) { + for _, order := range swapMsgStates { + if !order.Executed { + panic("not executed") + } + if order.RemainingOfferCoin.IsZero() { + if !order.Succeeded || !order.ToBeDeleted { + panic("broken state consistency for not matched order") + } + continue + } + // set toDelete, expired msgs + if currentHeight > order.OrderExpiryHeight { + if order.Succeeded || !order.ToBeDeleted { + panic("broken state consistency for fractional matched order") + } + continue + } + if expireThisHeight && currentHeight == order.OrderExpiryHeight { + order.ToBeDeleted = true + } + } +} + +// Check swap price validity using list of match result. +func CheckSwapPrice(matchResultXtoY, matchResultYtoX []MatchResult, swapPrice sdk.Dec) bool { + if len(matchResultXtoY) == 0 && len(matchResultYtoX) == 0 { + return true + } + // Check if it is greater than a value that can be a decimal error + for _, m := range matchResultXtoY { + if m.TransactedCoinAmt.Quo(swapPrice).Sub(m.ExchangedDemandCoinAmt).Abs().GT(sdk.OneDec()) { + return false + } + } + for _, m := range matchResultYtoX { + if m.TransactedCoinAmt.Mul(swapPrice).Sub(m.ExchangedDemandCoinAmt).Abs().GT(sdk.OneDec()) { + return false + } + } + return !swapPrice.IsZero() +} + +// Find matched orders and set status for msgs +func FindOrderMatch(direction OrderDirection, swapMsgStates []*SwapMsgState, executableAmt, swapPrice sdk.Dec, height int64) ( + matchResults []MatchResult, poolXDelta, poolYDelta sdk.Dec) { + poolXDelta = sdk.ZeroDec() + poolYDelta = sdk.ZeroDec() + + if executableAmt.IsZero() { + return + } + + if direction == DirectionXtoY { + sort.SliceStable(swapMsgStates, func(i, j int) bool { + return swapMsgStates[i].Msg.OrderPrice.GT(swapMsgStates[j].Msg.OrderPrice) + }) + } else if direction == DirectionYtoX { + sort.SliceStable(swapMsgStates, func(i, j int) bool { + return swapMsgStates[i].Msg.OrderPrice.LT(swapMsgStates[j].Msg.OrderPrice) + }) + } + + matchAmt := sdk.ZeroInt() + accumMatchAmt := sdk.ZeroInt() + var matchedSwapMsgStates []*SwapMsgState //nolint:prealloc + + for i, order := range swapMsgStates { + // include the matched order in matchAmt, matchedSwapMsgStates + if (direction == DirectionXtoY && order.Msg.OrderPrice.LT(swapPrice)) || + (direction == DirectionYtoX && order.Msg.OrderPrice.GT(swapPrice)) { + break + } + + matchAmt = matchAmt.Add(order.RemainingOfferCoin.Amount) + matchedSwapMsgStates = append(matchedSwapMsgStates, order) + + if i == len(swapMsgStates)-1 || !swapMsgStates[i+1].Msg.OrderPrice.Equal(order.Msg.OrderPrice) { + if matchAmt.IsPositive() { + var fractionalMatchRatio sdk.Dec + if accumMatchAmt.Add(matchAmt).ToDec().GTE(executableAmt) { + fractionalMatchRatio = executableAmt.Sub(accumMatchAmt.ToDec()).Quo(matchAmt.ToDec()) + if fractionalMatchRatio.GT(sdk.NewDec(1)) { + panic("fractionalMatchRatio should be between 0 and 1") + } + } else { + fractionalMatchRatio = sdk.OneDec() + } + if !fractionalMatchRatio.IsPositive() { + fractionalMatchRatio = sdk.OneDec() + } + for _, matchOrder := range matchedSwapMsgStates { + offerAmt := matchOrder.RemainingOfferCoin.Amount.ToDec() + matchResult := MatchResult{ + OrderDirection: direction, + OfferCoinAmt: offerAmt, + // TransactedCoinAmt is a value that should not be lost, so Ceil it conservatively considering the decimal error. + TransactedCoinAmt: offerAmt.Mul(fractionalMatchRatio).Ceil(), + SwapMsgState: matchOrder, + } + if matchResult.OfferCoinAmt.Sub(matchResult.TransactedCoinAmt).LTE(sdk.OneDec()) { + // Use ReservedOfferCoinFee to avoid decimal errors when OfferCoinAmt and TransactedCoinAmt are almost equal in value. + matchResult.OfferCoinFeeAmt = matchResult.SwapMsgState.ReservedOfferCoinFee.Amount.ToDec() + } else { + matchResult.OfferCoinFeeAmt = matchResult.SwapMsgState.ReservedOfferCoinFee.Amount.ToDec().Mul(fractionalMatchRatio) + } + if direction == DirectionXtoY { + matchResult.ExchangedDemandCoinAmt = matchResult.TransactedCoinAmt.Quo(swapPrice) + matchResult.ExchangedCoinFeeAmt = matchResult.OfferCoinFeeAmt.Quo(swapPrice) + } else if direction == DirectionYtoX { + matchResult.ExchangedDemandCoinAmt = matchResult.TransactedCoinAmt.Mul(swapPrice) + matchResult.ExchangedCoinFeeAmt = matchResult.OfferCoinFeeAmt.Mul(swapPrice) + } + // Check for differences above maximum decimal error + if matchResult.TransactedCoinAmt.GT(matchResult.OfferCoinAmt) { + panic("bad TransactedCoinAmt") + } + if matchResult.OfferCoinFeeAmt.GT(matchResult.OfferCoinAmt) && matchResult.OfferCoinFeeAmt.GT(sdk.OneDec()) { + panic("bad OfferCoinFeeAmt") + } + matchResults = append(matchResults, matchResult) + if direction == DirectionXtoY { + poolXDelta = poolXDelta.Add(matchResult.TransactedCoinAmt) + poolYDelta = poolYDelta.Sub(matchResult.ExchangedDemandCoinAmt) + } else if direction == DirectionYtoX { + poolXDelta = poolXDelta.Sub(matchResult.ExchangedDemandCoinAmt) + poolYDelta = poolYDelta.Add(matchResult.TransactedCoinAmt) + } + } + accumMatchAmt = accumMatchAmt.Add(matchAmt) + } + + matchAmt = sdk.ZeroInt() + matchedSwapMsgStates = matchedSwapMsgStates[:0] + } + } + return matchResults, poolXDelta, poolYDelta +} + +// UpdateSwapMsgStates updates SwapMsgStates using the MatchResults. +func UpdateSwapMsgStates(x, y sdk.Dec, xToY, yToX []*SwapMsgState, matchResultXtoY, matchResultYtoX []MatchResult) ( + []*SwapMsgState, []*SwapMsgState, sdk.Dec, sdk.Dec, sdk.Dec, sdk.Dec) { + sort.SliceStable(xToY, func(i, j int) bool { + return xToY[i].Msg.OrderPrice.GT(xToY[j].Msg.OrderPrice) + }) + sort.SliceStable(yToX, func(i, j int) bool { + return yToX[i].Msg.OrderPrice.LT(yToX[j].Msg.OrderPrice) + }) + + poolXDelta := sdk.ZeroDec() + poolYDelta := sdk.ZeroDec() + + // Variables to accumulate and offset the values of int 1 caused by decimal error + decimalErrorX := sdk.ZeroDec() + decimalErrorY := sdk.ZeroDec() + + for _, match := range append(matchResultXtoY, matchResultYtoX...) { + sms := match.SwapMsgState + if match.OrderDirection == DirectionXtoY { + poolXDelta = poolXDelta.Add(match.TransactedCoinAmt) + poolYDelta = poolYDelta.Sub(match.ExchangedDemandCoinAmt) + } else { + poolXDelta = poolXDelta.Sub(match.ExchangedDemandCoinAmt) + poolYDelta = poolYDelta.Add(match.TransactedCoinAmt) + } + if sms.RemainingOfferCoin.Amount.ToDec().Sub(match.TransactedCoinAmt).LTE(sdk.OneDec()) { + // when RemainingOfferCoin and TransactedCoinAmt are almost equal in value, corrects the decimal error and processes as a exact match. + sms.ExchangedOfferCoin.Amount = sms.ExchangedOfferCoin.Amount.Add(match.TransactedCoinAmt.TruncateInt()) + sms.RemainingOfferCoin.Amount = sms.RemainingOfferCoin.Amount.Sub(match.TransactedCoinAmt.TruncateInt()) + sms.ReservedOfferCoinFee.Amount = sms.ReservedOfferCoinFee.Amount.Sub(match.OfferCoinFeeAmt.TruncateInt()) + if sms.ExchangedOfferCoin.IsNegative() || sms.RemainingOfferCoin.IsNegative() || sms.ReservedOfferCoinFee.IsNegative() { + panic("negative coin amount after update") + } + if sms.RemainingOfferCoin.Amount.Equal(sdk.OneInt()) { + decimalErrorY = decimalErrorY.Add(sdk.OneDec()) + sms.RemainingOfferCoin.Amount = sdk.ZeroInt() + } + if !sms.RemainingOfferCoin.IsZero() || sms.ExchangedOfferCoin.Amount.GT(sms.Msg.OfferCoin.Amount) || + sms.ReservedOfferCoinFee.Amount.GT(sdk.OneInt()) { + panic("invalid state after update") + } else { + sms.Succeeded = true + sms.ToBeDeleted = true + } + } else { + // fractional match + sms.ExchangedOfferCoin.Amount = sms.ExchangedOfferCoin.Amount.Add(match.TransactedCoinAmt.TruncateInt()) + sms.RemainingOfferCoin.Amount = sms.RemainingOfferCoin.Amount.Sub(match.TransactedCoinAmt.TruncateInt()) + sms.ReservedOfferCoinFee.Amount = sms.ReservedOfferCoinFee.Amount.Sub(match.OfferCoinFeeAmt.TruncateInt()) + if sms.ExchangedOfferCoin.IsNegative() || sms.RemainingOfferCoin.IsNegative() || sms.ReservedOfferCoinFee.IsNegative() { + panic("negative coin amount after update") + } + sms.Succeeded = true + sms.ToBeDeleted = false + } + } + + // Offset accumulated decimal error values + poolXDelta = poolXDelta.Add(decimalErrorX) + poolYDelta = poolYDelta.Add(decimalErrorY) + + x = x.Add(poolXDelta) + y = y.Add(poolYDelta) + + return xToY, yToX, x, y, poolXDelta, poolYDelta +} diff --git a/x/liquidity/types/swap_test.go b/x/liquidity/types/swap_test.go new file mode 100644 index 00000000000..47ee3154f4c --- /dev/null +++ b/x/liquidity/types/swap_test.go @@ -0,0 +1,680 @@ +package types_test + +import ( + "encoding/json" + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/app" + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestSwapScenario(t *testing.T) { + // init test app and context + simapp, ctx := app.CreateTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + X := params.MinInitDepositAmount + Y := params.MinInitDepositAmount + + // init addresses for the test + addrs := app.AddTestAddrs(simapp, ctx, 20, params.PoolCreationFee) + + // Create pool + // The create pool msg is not run in batch, but is processed immediately. + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + // In case of deposit, withdraw, and swap msg, unlike other normal tx msgs, + // collect them in the batch and perform an execution at once at the endblock. + + // add a deposit to pool and run batch execution on endblock + app.TestDepositPool(t, simapp, ctx, X, Y, addrs[1:2], poolID, true) + + // next block, reinitialize batch and increase batchIndex at beginBlocker, + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + // Create swap msg for test purposes and put it in the batch. + price, _ := sdk.NewDecFromStr("1.1") + priceY, _ := sdk.NewDecFromStr("1.2") + xOfferCoins := []sdk.Coin{sdk.NewCoin(denomX, sdk.NewInt(10000))} + yOfferCoins := []sdk.Coin{sdk.NewCoin(denomY, sdk.NewInt(5000))} + xOrderPrices := []sdk.Dec{price} + yOrderPrices := []sdk.Dec{priceY} + xOrderAddrs := addrs[1:2] + yOrderAddrs := addrs[2:3] + _, batch := app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + _, batch = app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + _, batch = app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + _, batch = app.TestSwapPool(t, simapp, ctx, yOfferCoins, yOrderPrices, yOrderAddrs, poolID, false) + + // Set the execution status flag of messages to true. + msgs := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, batch) + for _, msg := range msgs { + msg.Executed = true + } + simapp.LiquidityKeeper.SetPoolBatchSwapMsgStatesByPointer(ctx, poolID, msgs) + + // Generate an orderbook by arranging swap messages in order price + orderMap, xToY, yToX := types.MakeOrderMap(msgs, denomX, denomY, false) + orderBook := orderMap.SortOrderBook() + currentPrice := X.Quo(Y).ToDec() + require.Equal(t, orderMap[xOrderPrices[0].String()].BuyOfferAmt, xOfferCoins[0].Amount.MulRaw(3)) + require.Equal(t, orderMap[xOrderPrices[0].String()].Price, xOrderPrices[0]) + + require.Equal(t, 3, len(xToY)) + require.Equal(t, 1, len(yToX)) + require.Equal(t, 3, len(orderMap[xOrderPrices[0].String()].SwapMsgStates)) + require.Equal(t, 1, len(orderMap[yOrderPrices[0].String()].SwapMsgStates)) + require.Equal(t, 3, len(orderBook[0].SwapMsgStates)) + require.Equal(t, 1, len(orderBook[1].SwapMsgStates)) + + require.Equal(t, len(orderBook), orderBook.Len()) + + fmt.Println(orderBook, currentPrice) + fmt.Println(xToY, yToX) + + types.ValidateStateAndExpireOrders(xToY, ctx.BlockHeight(), false) + types.ValidateStateAndExpireOrders(yToX, ctx.BlockHeight(), false) + + // The price and coins of swap messages in orderbook are calculated + // to derive match result with the price direction. + result, found := orderBook.Match(X.ToDec(), Y.ToDec()) + require.True(t, found) + require.NotEqual(t, types.NoMatch, result.MatchType) + + matchResultXtoY, poolXDeltaXtoY, poolYDeltaXtoY := types.FindOrderMatch(types.DirectionXtoY, xToY, result.EX, + result.SwapPrice, ctx.BlockHeight()) + matchResultYtoX, poolXDeltaYtoX, poolYDeltaYtoX := types.FindOrderMatch(types.DirectionYtoX, yToX, result.EY, + result.SwapPrice, ctx.BlockHeight()) + + xToY, yToX, XDec, YDec, poolXDelta2, poolYDelta2 := types.UpdateSwapMsgStates(X.ToDec(), Y.ToDec(), xToY, yToX, matchResultXtoY, matchResultYtoX) + + require.Equal(t, 0, types.CountNotMatchedMsgs(xToY)) + require.Equal(t, 0, types.CountFractionalMatchedMsgs(xToY)) + require.Equal(t, 1, types.CountNotMatchedMsgs(yToX)) + require.Equal(t, 0, types.CountFractionalMatchedMsgs(yToX)) + require.Equal(t, 3, len(xToY)) + require.Equal(t, 1, len(yToX)) + + fmt.Println(matchResultXtoY) + fmt.Println(poolXDeltaXtoY) + fmt.Println(poolYDeltaXtoY) + + fmt.Println(poolXDeltaYtoX, poolYDeltaYtoX) + fmt.Println(poolXDelta2, poolYDelta2) + fmt.Println(XDec, YDec) + + // Verify swap result by creating an orderbook with remaining messages that have been matched and not transacted. + orderMapExecuted, _, _ := types.MakeOrderMap(append(xToY, yToX...), denomX, denomY, true) + orderBookExecuted := orderMapExecuted.SortOrderBook() + lastPrice := XDec.Quo(YDec) + fmt.Println("lastPrice", lastPrice) + fmt.Println("X", XDec) + fmt.Println("Y", YDec) + require.True(t, orderBookExecuted.Validate(lastPrice)) + + require.Equal(t, 0, types.CountNotMatchedMsgs(orderMapExecuted[xOrderPrices[0].String()].SwapMsgStates)) + require.Equal(t, 1, types.CountNotMatchedMsgs(orderMapExecuted[yOrderPrices[0].String()].SwapMsgStates)) + require.Equal(t, 1, types.CountNotMatchedMsgs(orderBookExecuted[0].SwapMsgStates)) + + types.ValidateStateAndExpireOrders(xToY, ctx.BlockHeight(), true) + types.ValidateStateAndExpireOrders(yToX, ctx.BlockHeight(), true) + + orderMapCleared, _, _ := types.MakeOrderMap(append(xToY, yToX...), denomX, denomY, true) + orderBookCleared := orderMapCleared.SortOrderBook() + require.True(t, orderBookCleared.Validate(lastPrice)) + + require.Equal(t, 0, types.CountNotMatchedMsgs(orderMapCleared[xOrderPrices[0].String()].SwapMsgStates)) + require.Equal(t, 0, types.CountNotMatchedMsgs(orderMapCleared[yOrderPrices[0].String()].SwapMsgStates)) + require.Equal(t, 0, len(orderBookCleared)) + + // next block + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + // test genesisState with export, init + genesis := simapp.LiquidityKeeper.ExportGenesis(ctx) + simapp.LiquidityKeeper.InitGenesis(ctx, *genesis) + err := types.ValidateGenesis(*genesis) + require.NoError(t, err) + genesisNew := simapp.LiquidityKeeper.ExportGenesis(ctx) + err = types.ValidateGenesis(*genesisNew) + require.NoError(t, err) + require.Equal(t, genesis, genesisNew) + for _, record := range genesisNew.PoolRecords { + err = record.Validate() + require.NoError(t, err) + } + + // validate genesis fail case + batch.DepositMsgIndex = 0 + simapp.LiquidityKeeper.SetPoolBatch(ctx, batch) + genesisNew = simapp.LiquidityKeeper.ExportGenesis(ctx) + err = types.ValidateGenesis(*genesisNew) + require.ErrorIs(t, err, types.ErrBadBatchMsgIndex) + batch.WithdrawMsgIndex = 0 + simapp.LiquidityKeeper.SetPoolBatch(ctx, batch) + genesisNew = simapp.LiquidityKeeper.ExportGenesis(ctx) + err = types.ValidateGenesis(*genesisNew) + require.ErrorIs(t, err, types.ErrBadBatchMsgIndex) + batch.SwapMsgIndex = 20 + simapp.LiquidityKeeper.SetPoolBatch(ctx, batch) + genesisNew = simapp.LiquidityKeeper.ExportGenesis(ctx) + err = types.ValidateGenesis(*genesisNew) + require.ErrorIs(t, err, types.ErrBadBatchMsgIndex) +} + +func TestMaxOrderRatio(t *testing.T) { + simapp, ctx := app.CreateTestInput() + simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) + params := simapp.LiquidityKeeper.GetParams(ctx) + + // define test denom X, Y for Liquidity Pool + denomX, denomY := types.AlphabeticalDenomPair(DenomX, DenomY) + + X := params.MinInitDepositAmount + Y := params.MinInitDepositAmount + + addrs := app.AddTestAddrs(simapp, ctx, 20, params.PoolCreationFee) + poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) + + // begin block, init + app.TestDepositPool(t, simapp, ctx, X, Y, addrs[1:2], poolID, true) + + // next block + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) + + maxOrderRatio := params.MaxOrderAmountRatio + + // Success case, not exceed GetMaxOrderRatio orders + priceBuy, _ := sdk.NewDecFromStr("1.1") + priceSell, _ := sdk.NewDecFromStr("1.2") + + offerCoin := sdk.NewCoin(denomX, sdk.NewInt(1000)) + offerCoinY := sdk.NewCoin(denomY, sdk.NewInt(1000)) + + app.SaveAccountWithFee(simapp, ctx, addrs[1], sdk.NewCoins(offerCoin), offerCoin) + app.SaveAccountWithFee(simapp, ctx, addrs[2], sdk.NewCoins(offerCoinY), offerCoinY) + + msgBuy := types.NewMsgSwapWithinBatch(addrs[1], poolID, DefaultSwapTypeId, offerCoin, DenomY, priceBuy, params.SwapFeeRate) + msgSell := types.NewMsgSwapWithinBatch(addrs[2], poolID, DefaultSwapTypeId, offerCoinY, DenomX, priceSell, params.SwapFeeRate) + + _, err := simapp.LiquidityKeeper.SwapWithinBatch(ctx, msgBuy, 0) + require.NoError(t, err) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, msgSell, 0) + require.NoError(t, err) + + // Fail case, exceed GetMaxOrderRatio orders + offerCoin = sdk.NewCoin(denomX, X) + offerCoinY = sdk.NewCoin(denomY, Y) + + app.SaveAccountWithFee(simapp, ctx, addrs[1], sdk.NewCoins(offerCoin), offerCoin) + app.SaveAccountWithFee(simapp, ctx, addrs[2], sdk.NewCoins(offerCoinY), offerCoinY) + + msgBuy = types.NewMsgSwapWithinBatch(addrs[1], poolID, DefaultSwapTypeId, offerCoin, DenomY, priceBuy, params.SwapFeeRate) + msgSell = types.NewMsgSwapWithinBatch(addrs[2], poolID, DefaultSwapTypeId, offerCoinY, DenomX, priceSell, params.SwapFeeRate) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, msgBuy, 0) + require.Equal(t, types.ErrExceededMaxOrderable, err) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, msgSell, 0) + require.Equal(t, types.ErrExceededMaxOrderable, err) + + // Success case, same GetMaxOrderRatio orders + offerCoin = sdk.NewCoin(denomX, X.ToDec().Mul(maxOrderRatio).TruncateInt()) + offerCoinY = sdk.NewCoin(denomY, Y.ToDec().Mul(maxOrderRatio).TruncateInt()) + + app.SaveAccountWithFee(simapp, ctx, addrs[1], sdk.NewCoins(offerCoin), offerCoin) + app.SaveAccountWithFee(simapp, ctx, addrs[2], sdk.NewCoins(offerCoinY), offerCoinY) + + msgBuy = types.NewMsgSwapWithinBatch(addrs[1], poolID, DefaultSwapTypeId, offerCoin, DenomY, priceBuy, params.SwapFeeRate) + msgSell = types.NewMsgSwapWithinBatch(addrs[2], poolID, DefaultSwapTypeId, offerCoinY, DenomX, priceSell, params.SwapFeeRate) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, msgBuy, 0) + require.NoError(t, err) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, msgSell, 0) + require.NoError(t, err) + + // Success case, same GetMaxOrderRatio orders + offerCoin = sdk.NewCoin(denomX, X.ToDec().Mul(maxOrderRatio).TruncateInt().AddRaw(1)) + offerCoinY = sdk.NewCoin(denomY, Y.ToDec().Mul(maxOrderRatio).TruncateInt().AddRaw(1)) + + offerCoin = sdk.NewCoin(denomX, params.MinInitDepositAmount.Quo(sdk.NewInt(2))) + offerCoinY = sdk.NewCoin(denomY, params.MinInitDepositAmount.Quo(sdk.NewInt(10))) + app.SaveAccountWithFee(simapp, ctx, addrs[1], sdk.NewCoins(offerCoin), offerCoin) + app.SaveAccountWithFee(simapp, ctx, addrs[2], sdk.NewCoins(offerCoinY), offerCoinY) + + msgBuy = types.NewMsgSwapWithinBatch(addrs[1], poolID, DefaultSwapTypeId, offerCoin, DenomY, priceBuy, params.SwapFeeRate) + msgSell = types.NewMsgSwapWithinBatch(addrs[2], poolID, DefaultSwapTypeId, offerCoinY, DenomX, priceSell, params.SwapFeeRate) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, msgBuy, 0) + require.Equal(t, types.ErrExceededMaxOrderable, err) + + _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, msgSell, 0) + require.NoError(t, err) +} + +func TestOrderBookSort(t *testing.T) { + orderMap := make(types.OrderMap) + a, _ := sdk.NewDecFromStr("0.1") + b, _ := sdk.NewDecFromStr("0.2") + c, _ := sdk.NewDecFromStr("0.3") + orderMap[a.String()] = types.Order{ + Price: a, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.ZeroInt(), + } + orderMap[b.String()] = types.Order{ + Price: b, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.ZeroInt(), + } + orderMap[c.String()] = types.Order{ + Price: c, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.ZeroInt(), + } + // make orderbook to sort orderMap + orderBook := orderMap.SortOrderBook() + fmt.Println(orderBook) + + res := orderBook.Less(0, 1) + require.True(t, res) + res = orderBook.Less(1, 2) + require.True(t, res) + res = orderBook.Less(2, 1) + require.False(t, res) + + orderBook.Swap(1, 2) + fmt.Println(orderBook) + require.Equal(t, c, orderBook[1].Price) + require.Equal(t, b, orderBook[2].Price) + + orderBook.Sort() + fmt.Println(orderBook) + require.Equal(t, a, orderBook[0].Price) + require.Equal(t, b, orderBook[1].Price) + require.Equal(t, c, orderBook[2].Price) + + orderBook.Reverse() + fmt.Println(orderBook) + require.Equal(t, a, orderBook[2].Price) + require.Equal(t, b, orderBook[1].Price) + require.Equal(t, c, orderBook[0].Price) +} + +func TestExecutableAmt(t *testing.T) { + orderMap := make(types.OrderMap) + a, _ := sdk.NewDecFromStr("0.1") + b, _ := sdk.NewDecFromStr("0.2") + c, _ := sdk.NewDecFromStr("0.3") + orderMap[a.String()] = types.Order{ + Price: a, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.NewInt(30000000), + } + orderMap[b.String()] = types.Order{ + Price: b, + BuyOfferAmt: sdk.NewInt(90000000), + SellOfferAmt: sdk.ZeroInt(), + } + orderMap[c.String()] = types.Order{ + Price: c, + BuyOfferAmt: sdk.NewInt(50000000), + SellOfferAmt: sdk.ZeroInt(), + } + // make orderbook to sort orderMap + orderBook := orderMap.SortOrderBook() + + executableBuyAmtX, executableSellAmtY := orderBook.ExecutableAmt(b) + require.Equal(t, sdk.NewInt(140000000), executableBuyAmtX) + require.Equal(t, sdk.NewInt(30000000), executableSellAmtY) +} + +func TestPriceDirection(t *testing.T) { + // increase case + orderMap := make(types.OrderMap) + a, _ := sdk.NewDecFromStr("1") + b, _ := sdk.NewDecFromStr("1.1") + c, _ := sdk.NewDecFromStr("1.2") + orderMap[a.String()] = types.Order{ + Price: a, + BuyOfferAmt: sdk.NewInt(40000000), + SellOfferAmt: sdk.ZeroInt(), + } + orderMap[b.String()] = types.Order{ + Price: b, + BuyOfferAmt: sdk.NewInt(40000000), + SellOfferAmt: sdk.ZeroInt(), + } + orderMap[c.String()] = types.Order{ + Price: c, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.NewInt(20000000), + } + // make orderbook to sort orderMap + orderBook := orderMap.SortOrderBook() + poolPrice, _ := sdk.NewDecFromStr("1.0") + result := orderBook.PriceDirection(poolPrice) + require.Equal(t, types.Increasing, result) + + // decrease case + orderMap = make(types.OrderMap) + a, _ = sdk.NewDecFromStr("0.7") + b, _ = sdk.NewDecFromStr("0.9") + c, _ = sdk.NewDecFromStr("0.8") + orderMap[a.String()] = types.Order{ + Price: a, + BuyOfferAmt: sdk.NewInt(20000000), + SellOfferAmt: sdk.ZeroInt(), + } + orderMap[b.String()] = types.Order{ + Price: b, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.NewInt(40000000), + } + orderMap[c.String()] = types.Order{ + Price: c, + BuyOfferAmt: sdk.NewInt(10000000), + SellOfferAmt: sdk.ZeroInt(), + } + // make orderbook to sort orderMap + orderBook = orderMap.SortOrderBook() + poolPrice, _ = sdk.NewDecFromStr("1.0") + result = orderBook.PriceDirection(poolPrice) + require.Equal(t, types.Decreasing, result) + + // stay case + orderMap = make(types.OrderMap) + a, _ = sdk.NewDecFromStr("1.0") + + orderMap[a.String()] = types.Order{ + Price: a, + BuyOfferAmt: sdk.NewInt(50000000), + SellOfferAmt: sdk.NewInt(50000000), + } + orderBook = orderMap.SortOrderBook() + poolPrice, _ = sdk.NewDecFromStr("1.0") + result = orderBook.PriceDirection(poolPrice) + require.Equal(t, types.Staying, result) +} + +func TestComputePriceDirection(t *testing.T) { + // increase case + orderMap := make(types.OrderMap) + a, _ := sdk.NewDecFromStr("1") + b, _ := sdk.NewDecFromStr("1.1") + c, _ := sdk.NewDecFromStr("1.2") + orderMap[a.String()] = types.Order{ + Price: a, + BuyOfferAmt: sdk.NewInt(40000000), + SellOfferAmt: sdk.ZeroInt(), + } + orderMap[b.String()] = types.Order{ + Price: b, + BuyOfferAmt: sdk.NewInt(40000000), + SellOfferAmt: sdk.ZeroInt(), + } + orderMap[c.String()] = types.Order{ + Price: c, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.NewInt(20000000), + } + // make orderbook to sort orderMap + orderBook := orderMap.SortOrderBook() + + X := orderMap[a.String()].BuyOfferAmt.ToDec().Add(orderMap[b.String()].BuyOfferAmt.ToDec()) + Y := orderMap[c.String()].SellOfferAmt.ToDec() + + poolPrice := X.Quo(Y) + direction := orderBook.PriceDirection(poolPrice) + result, found := orderBook.Match(X, Y) + result2, found2 := orderBook.CalculateMatch(direction, X, Y) + require.Equal(t, found2, found) + require.Equal(t, result2, result) + + // decrease case + orderMap = make(types.OrderMap) + a, _ = sdk.NewDecFromStr("0.7") + b, _ = sdk.NewDecFromStr("0.9") + c, _ = sdk.NewDecFromStr("0.8") + orderMap[a.String()] = types.Order{ + Price: a, + BuyOfferAmt: sdk.NewInt(20000000), + SellOfferAmt: sdk.ZeroInt(), + } + orderMap[b.String()] = types.Order{ + Price: b, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.NewInt(40000000), + } + orderMap[c.String()] = types.Order{ + Price: c, + BuyOfferAmt: sdk.NewInt(10000000), + SellOfferAmt: sdk.ZeroInt(), + } + // make orderbook to sort orderMap + orderBook = orderMap.SortOrderBook() + + X = orderMap[a.String()].BuyOfferAmt.ToDec().Add(orderMap[c.String()].BuyOfferAmt.ToDec()) + Y = orderMap[b.String()].SellOfferAmt.ToDec() + + poolPrice = X.Quo(Y) + direction = orderBook.PriceDirection(poolPrice) + result, found = orderBook.Match(X, Y) + result2, found2 = orderBook.CalculateMatch(direction, X, Y) + require.Equal(t, found2, found) + require.Equal(t, result2, result) + + // stay case + orderMap = make(types.OrderMap) + a, _ = sdk.NewDecFromStr("1.0") + + orderMap[a.String()] = types.Order{ + Price: a, + BuyOfferAmt: sdk.NewInt(50000000), + SellOfferAmt: sdk.NewInt(50000000), + } + orderBook = orderMap.SortOrderBook() + + X = orderMap[a.String()].BuyOfferAmt.ToDec() + Y = orderMap[a.String()].SellOfferAmt.ToDec() + poolPrice = X.Quo(Y) + + result, _ = orderBook.Match(X, Y) + result2 = orderBook.CalculateMatchStay(poolPrice) + require.Equal(t, result2, result) +} + +func TestCalculateMatchStay(t *testing.T) { + currentPrice := sdk.MustNewDecFromStr("1.0") + orderBook := types.OrderBook{ + {Price: sdk.MustNewDecFromStr("1.0"), BuyOfferAmt: sdk.NewInt(5), SellOfferAmt: sdk.NewInt(7)}, + } + require.Equal(t, types.Staying, orderBook.PriceDirection(currentPrice)) + r := orderBook.CalculateMatchStay(currentPrice) + require.Equal(t, sdk.NewDec(5), r.EX) + require.Equal(t, sdk.NewDec(5), r.EY) +} + +// Match Stay case with fractional match type +func TestCalculateMatchStayEdgeCase(t *testing.T) { + currentPrice, err := sdk.NewDecFromStr("1.844380246375231658") + require.NoError(t, err) + var orderBook types.OrderBook + orderbookEdgeCase := `[{"Price":"1.827780824157854573","BuyOfferAmt":"12587364000","SellOfferAmt":"6200948000","BatchPoolSwapMsgs":[{"msg_index":12,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2097894000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2097894000"},"demand_coin_denom":"denomY","order_price":"1.827780824157854573"}},{"msg_index":16,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4669506000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4669506000"},"demand_coin_denom":"denomY","order_price":"1.827780824157854573"}},{"msg_index":23,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"609066000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"609066000"},"demand_coin_denom":"denomY","order_price":"1.827780824157854573"}},{"msg_index":39,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5210898000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfckxufsg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5210898000"},"demand_coin_denom":"denomY","order_price":"1.827780824157854573"}},{"msg_index":56,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1284220000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1284220000"},"demand_coin_denom":"denomX","order_price":"1.827780824157854573"}},{"msg_index":78,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1981368000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfhft040s","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1981368000"},"demand_coin_denom":"denomX","order_price":"1.827780824157854573"}},{"msg_index":85,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2935360000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2yrhrufk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2935360000"},"demand_coin_denom":"denomX","order_price":"1.827780824157854573"}}]},{"Price":"1.829625204404229805","BuyOfferAmt":"9203664000","SellOfferAmt":"6971480000","BatchPoolSwapMsgs":[{"msg_index":18,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5210898000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5210898000"},"demand_coin_denom":"denomY","order_price":"1.829625204404229805"}},{"msg_index":36,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3992766000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf46wwkua","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3992766000"},"demand_coin_denom":"denomY","order_price":"1.829625204404229805"}},{"msg_index":44,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3155512000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3155512000"},"demand_coin_denom":"denomX","order_price":"1.829625204404229805"}},{"msg_index":55,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"513688000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"513688000"},"demand_coin_denom":"denomX","order_price":"1.829625204404229805"}},{"msg_index":61,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3302280000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3302280000"},"demand_coin_denom":"denomX","order_price":"1.829625204404229805"}}]},{"Price":"1.831469584650605036","BuyOfferAmt":"18001284000","SellOfferAmt":"2311596000","BatchPoolSwapMsgs":[{"msg_index":21,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3248352000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3248352000"},"demand_coin_denom":"denomY","order_price":"1.831469584650605036"}},{"msg_index":32,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5007876000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5007876000"},"demand_coin_denom":"denomY","order_price":"1.831469584650605036"}},{"msg_index":33,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5955312000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5955312000"},"demand_coin_denom":"denomY","order_price":"1.831469584650605036"}},{"msg_index":34,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3789744000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3789744000"},"demand_coin_denom":"denomY","order_price":"1.831469584650605036"}},{"msg_index":65,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2311596000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2311596000"},"demand_coin_denom":"denomX","order_price":"1.831469584650605036"}}]},{"Price":"1.833313964896980268","BuyOfferAmt":"12113646000","SellOfferAmt":"4806652000","BatchPoolSwapMsgs":[{"msg_index":6,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6632052000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6632052000"},"demand_coin_denom":"denomY","order_price":"1.833313964896980268"}},{"msg_index":28,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5481594000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5481594000"},"demand_coin_denom":"denomY","order_price":"1.833313964896980268"}},{"msg_index":41,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"660456000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"660456000"},"demand_coin_denom":"denomX","order_price":"1.833313964896980268"}},{"msg_index":64,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2421672000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2421672000"},"demand_coin_denom":"denomX","order_price":"1.833313964896980268"}},{"msg_index":73,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1724524000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1724524000"},"demand_coin_denom":"denomX","order_price":"1.833313964896980268"}}]},{"Price":"1.835158345143355500","BuyOfferAmt":"0","SellOfferAmt":"6421100000","BatchPoolSwapMsgs":[{"msg_index":47,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2715208000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2715208000"},"demand_coin_denom":"denomX","order_price":"1.835158345143355500"}},{"msg_index":58,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2678516000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2678516000"},"demand_coin_denom":"denomX","order_price":"1.835158345143355500"}},{"msg_index":82,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1027376000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2p3t40m7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1027376000"},"demand_coin_denom":"denomX","order_price":"1.835158345143355500"}}]},{"Price":"1.837002725389730731","BuyOfferAmt":"9135990000","SellOfferAmt":"3852660000","BatchPoolSwapMsgs":[{"msg_index":13,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"744414000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"744414000"},"demand_coin_denom":"denomY","order_price":"1.837002725389730731"}},{"msg_index":19,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5143224000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5143224000"},"demand_coin_denom":"denomY","order_price":"1.837002725389730731"}},{"msg_index":22,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"541392000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"541392000"},"demand_coin_denom":"denomY","order_price":"1.837002725389730731"}},{"msg_index":35,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2706960000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf58c6rp0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2706960000"},"demand_coin_denom":"denomY","order_price":"1.837002725389730731"}},{"msg_index":48,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2274904000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2274904000"},"demand_coin_denom":"denomX","order_price":"1.837002725389730731"}},{"msg_index":51,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1394296000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1394296000"},"demand_coin_denom":"denomX","order_price":"1.837002725389730731"}},{"msg_index":80,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"183460000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfetsgud6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"183460000"},"demand_coin_denom":"denomX","order_price":"1.837002725389730731"}}]},{"Price":"1.838847105636105963","BuyOfferAmt":"6226008000","SellOfferAmt":"2715208000","BatchPoolSwapMsgs":[{"msg_index":5,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6226008000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6226008000"},"demand_coin_denom":"denomY","order_price":"1.838847105636105963"}},{"msg_index":43,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2715208000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2715208000"},"demand_coin_denom":"denomX","order_price":"1.838847105636105963"}}]},{"Price":"1.840691485882481195","BuyOfferAmt":"6496704000","SellOfferAmt":"3155512000","BatchPoolSwapMsgs":[{"msg_index":8,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6496704000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6496704000"},"demand_coin_denom":"denomY","order_price":"1.840691485882481195"}},{"msg_index":81,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3155512000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2qvap6xv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3155512000"},"demand_coin_denom":"denomX","order_price":"1.840691485882481195"}}]},{"Price":"1.842535866128856426","BuyOfferAmt":"0","SellOfferAmt":"1137452000","BatchPoolSwapMsgs":[{"msg_index":45,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1137452000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1137452000"},"demand_coin_denom":"denomX","order_price":"1.842535866128856426"}}]},{"Price":"1.844380246375231658","BuyOfferAmt":"15700368000","SellOfferAmt":"2274904000","BatchPoolSwapMsgs":[{"msg_index":14,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"1759524000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"1759524000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":24,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"1624176000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"1624176000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":25,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3248352000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3248352000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":29,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4263462000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4263462000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":31,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4804854000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4804854000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":59,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1651140000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1651140000"},"demand_coin_denom":"denomX","order_price":"1.844380246375231658"}},{"msg_index":62,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"623764000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"623764000"},"demand_coin_denom":"denomX","order_price":"1.844380246375231658"}}]},{"Price":"1.846224626621606890","BuyOfferAmt":"19963830000","SellOfferAmt":"3338972000","BatchPoolSwapMsgs":[{"msg_index":11,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6429030000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6429030000"},"demand_coin_denom":"denomY","order_price":"1.846224626621606890"}},{"msg_index":20,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5143224000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5143224000"},"demand_coin_denom":"denomY","order_price":"1.846224626621606890"}},{"msg_index":27,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2300916000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2300916000"},"demand_coin_denom":"denomY","order_price":"1.846224626621606890"}},{"msg_index":38,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6090660000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfhft040s","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6090660000"},"demand_coin_denom":"denomY","order_price":"1.846224626621606890"}},{"msg_index":42,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"660456000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"660456000"},"demand_coin_denom":"denomX","order_price":"1.846224626621606890"}},{"msg_index":68,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2678516000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2678516000"},"demand_coin_denom":"denomX","order_price":"1.846224626621606890"}}]},{"Price":"1.848069006867982121","BuyOfferAmt":"0","SellOfferAmt":"3302280000","BatchPoolSwapMsgs":[{"msg_index":46,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2201520000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2201520000"},"demand_coin_denom":"denomX","order_price":"1.848069006867982121"}},{"msg_index":70,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1100760000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1100760000"},"demand_coin_denom":"denomX","order_price":"1.848069006867982121"}}]},{"Price":"1.849913387114357353","BuyOfferAmt":"2233242000","SellOfferAmt":"10420528000","BatchPoolSwapMsgs":[{"msg_index":4,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2233242000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2233242000"},"demand_coin_denom":"denomY","order_price":"1.849913387114357353"}},{"msg_index":54,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"917300000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"917300000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":60,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3485740000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3485740000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":63,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"697148000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"697148000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":66,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2421672000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2421672000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":84,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1357604000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2rzw5vgn","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1357604000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":87,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1541064000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2xsjzl6m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1541064000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}}]},{"Price":"1.851757767360732585","BuyOfferAmt":"23550552000","SellOfferAmt":"1577756000","BatchPoolSwapMsgs":[{"msg_index":1,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5075550000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5075550000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":7,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4128114000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4128114000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":9,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4940202000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4940202000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":15,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3113004000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3113004000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":26,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6293682000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6293682000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":67,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"146768000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"146768000"},"demand_coin_denom":"denomX","order_price":"1.851757767360732585"}},{"msg_index":71,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1430988000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1430988000"},"demand_coin_denom":"denomX","order_price":"1.851757767360732585"}}]},{"Price":"1.853602147607107816","BuyOfferAmt":"3519048000","SellOfferAmt":"5577184000","BatchPoolSwapMsgs":[{"msg_index":10,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3519048000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3519048000"},"demand_coin_denom":"denomY","order_price":"1.853602147607107816"}},{"msg_index":52,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"403612000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"403612000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":53,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"770532000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"770532000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":72,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"146768000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"146768000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":74,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3155512000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3155512000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":75,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"183460000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf58c6rp0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"183460000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":76,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"917300000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf46wwkua","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"917300000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}}]},{"Price":"1.855446527853483048","BuyOfferAmt":"5752290000","SellOfferAmt":"1357604000","BatchPoolSwapMsgs":[{"msg_index":3,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3654396000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3654396000"},"demand_coin_denom":"denomY","order_price":"1.855446527853483048"}},{"msg_index":17,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2097894000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2097894000"},"demand_coin_denom":"denomY","order_price":"1.855446527853483048"}},{"msg_index":49,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1357604000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1357604000"},"demand_coin_denom":"denomX","order_price":"1.855446527853483048"}}]},{"Price":"1.857290908099858280","BuyOfferAmt":"2774634000","SellOfferAmt":"4256272000","BatchPoolSwapMsgs":[{"msg_index":37,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2774634000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfk5amqjz","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2774634000"},"demand_coin_denom":"denomY","order_price":"1.857290908099858280"}},{"msg_index":50,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2128136000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2128136000"},"demand_coin_denom":"denomX","order_price":"1.857290908099858280"}},{"msg_index":77,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"256844000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfk5amqjz","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"256844000"},"demand_coin_denom":"denomX","order_price":"1.857290908099858280"}},{"msg_index":83,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1871292000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2zlcqe4p","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1871292000"},"demand_coin_denom":"denomX","order_price":"1.857290908099858280"}}]},{"Price":"1.859135288346233511","BuyOfferAmt":"10760166000","SellOfferAmt":"5283648000","BatchPoolSwapMsgs":[{"msg_index":2,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"1421154000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"1421154000"},"demand_coin_denom":"denomY","order_price":"1.859135288346233511"}},{"msg_index":30,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4331136000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4331136000"},"demand_coin_denom":"denomY","order_price":"1.859135288346233511"}},{"msg_index":40,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5007876000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfetsgud6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5007876000"},"demand_coin_denom":"denomY","order_price":"1.859135288346233511"}},{"msg_index":57,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1137452000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1137452000"},"demand_coin_denom":"denomX","order_price":"1.859135288346233511"}},{"msg_index":69,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"293536000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"293536000"},"demand_coin_denom":"denomX","order_price":"1.859135288346233511"}},{"msg_index":79,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3302280000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfckxufsg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3302280000"},"demand_coin_denom":"denomX","order_price":"1.859135288346233511"}},{"msg_index":86,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"550380000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c297phf5y","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"550380000"},"demand_coin_denom":"denomX","order_price":"1.859135288346233511"}}]}]` + json.Unmarshal([]byte(orderbookEdgeCase), &orderBook) + r := orderBook.CalculateMatchStay(currentPrice) + require.Equal(t, types.FractionalMatch, r.MatchType) + // stay case with fractional +} + +// Match Stay case with no match type +func TestCalculateNoMatchEdgeCase(t *testing.T) { + currentPrice, err := sdk.NewDecFromStr("1.007768598527187219") + require.NoError(t, err) + var orderBook types.OrderBook + orderbookEdgeCase := `[{"Price":"1.007768598527187219","BuyOfferAmt":"0","SellOfferAmt":"417269600","BatchPoolSwapMsgs":[{"msg_index":1,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"417269600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"417269600"},"demand_coin_denom":"denomX","order_price":"1.007768598527187219"}}]},{"Price":"1.011799672921295968","BuyOfferAmt":"0","SellOfferAmt":"2190665400","BatchPoolSwapMsgs":[{"msg_index":2,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2190665400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2190665400"},"demand_coin_denom":"denomX","order_price":"1.011799672921295968"}}]}]` + json.Unmarshal([]byte(orderbookEdgeCase), &orderBook) + r := orderBook.CalculateMatchStay(currentPrice) + require.Equal(t, types.NoMatch, r.MatchType) + // stay case with fractional +} + +// Reproduce GetOrderMapEdgeCase, selling Y for X case, ErrInvalidDenom case +func TestMakeOrderMapEdgeCase(t *testing.T) { + onlyNotMatched := false + var swapMsgs []*types.SwapMsgState + swapMsgsJson := `[{"msg_index":1,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"19228500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"19228500"},"demand_coin_denom":"denomY","order_price":"0.027506527499265415"}},{"msg_index":2,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":3,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"23501500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"23501500"},"demand_coin_denom":"denomY","order_price":"0.027616663745508720"}},{"msg_index":4,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"200831000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"200831000"},"demand_coin_denom":"denomY","order_price":"0.027589129683947893"}},{"msg_index":5,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"160237500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"160237500"},"demand_coin_denom":"denomY","order_price":"0.027313789068339631"}},{"msg_index":6,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"175193000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"175193000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":7,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"183739000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"183739000"},"demand_coin_denom":"denomY","order_price":"0.027699265930191198"}},{"msg_index":8,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"32047500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"32047500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":9,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"111098000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"111098000"},"demand_coin_denom":"denomY","order_price":"0.027286255006778805"}},{"msg_index":10,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"166647000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"166647000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":11,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"98279000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"98279000"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":12,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"8546000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"8546000"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":13,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"87596500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"87596500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":14,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"111098000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"111098000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":15,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"38457000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"38457000"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":16,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"153828000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"153828000"},"demand_coin_denom":"denomY","order_price":"0.027616663745508720"}},{"msg_index":17,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"70504500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"70504500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":18,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"47003000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"47003000"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":19,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"132463000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"132463000"},"demand_coin_denom":"denomY","order_price":"0.027726799991752025"}},{"msg_index":20,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"66231500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"66231500"},"demand_coin_denom":"denomY","order_price":"0.027561595622387067"}},{"msg_index":21,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"119644000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"119644000"},"demand_coin_denom":"denomY","order_price":"0.027506527499265415"}},{"msg_index":22,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"17092000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"17092000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":23,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"209377000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"209377000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":24,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"207240500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"207240500"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":25,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"155964500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"155964500"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":26,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"194421500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"194421500"},"demand_coin_denom":"denomY","order_price":"0.027286255006778805"}},{"msg_index":27,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"102552000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"102552000"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":28,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"151691500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"151691500"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":29,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"113234500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"113234500"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":30,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"117507500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"117507500"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":31,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":32,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"200831000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"200831000"},"demand_coin_denom":"denomY","order_price":"0.027534061560826241"}},{"msg_index":33,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027726799991752025"}},{"msg_index":34,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"98279000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"98279000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":35,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"76914000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf58c6rp0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"76914000"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":36,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"23501500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf46wwkua","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"23501500"},"demand_coin_denom":"denomY","order_price":"0.027754334053312851"}},{"msg_index":37,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4733282800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4733282800"},"demand_coin_denom":"denomX","order_price":"0.027699265930191198"}},{"msg_index":38,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3957334800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3957334800"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":39,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2483033600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2483033600"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":40,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5509230800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5509230800"},"demand_coin_denom":"denomX","order_price":"0.027561595622387067"}},{"msg_index":41,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2327844000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2327844000"},"demand_coin_denom":"denomX","order_price":"0.027423925314582936"}},{"msg_index":42,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4733282800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4733282800"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":43,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7061126800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7061126800"},"demand_coin_denom":"denomX","order_price":"0.027726799991752025"}},{"msg_index":44,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4655688000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4655688000"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":45,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3026197200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3026197200"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":46,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7293911200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7293911200"},"demand_coin_denom":"denomX","order_price":"0.027616663745508720"}},{"msg_index":47,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4810877600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4810877600"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":48,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4345308800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4345308800"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":49,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5509230800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5509230800"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":50,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4190119200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4190119200"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":51,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"543163600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"543163600"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":52,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4578093200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4578093200"},"demand_coin_denom":"denomX","order_price":"0.027506527499265415"}},{"msg_index":53,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6517963200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6517963200"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":54,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4190119200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4190119200"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":55,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1939870000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1939870000"},"demand_coin_denom":"denomX","order_price":"0.027754334053312851"}},{"msg_index":56,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1163922000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1163922000"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":57,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5897204800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5897204800"},"demand_coin_denom":"denomX","order_price":"0.027644197807069546"}},{"msg_index":58,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"155189600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"155189600"},"demand_coin_denom":"denomX","order_price":"0.027671731868630372"}},{"msg_index":59,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2250249200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2250249200"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":60,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2948602400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2948602400"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":61,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7449100800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7449100800"},"demand_coin_denom":"denomX","order_price":"0.027313789068339631"}},{"msg_index":62,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6129989200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6129989200"},"demand_coin_denom":"denomX","order_price":"0.027341323129900457"}},{"msg_index":63,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3491766000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3491766000"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":64,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6362773600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6362773600"},"demand_coin_denom":"denomX","order_price":"0.027726799991752025"}},{"msg_index":65,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7138721600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7138721600"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":66,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3724550400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3724550400"},"demand_coin_denom":"denomX","order_price":"0.027616663745508720"}},{"msg_index":67,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3103792000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3103792000"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":68,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"232784400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"232784400"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":69,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6052394400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6052394400"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":70,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5121256800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5121256800"},"demand_coin_denom":"denomX","order_price":"0.027644197807069546"}}]` + json.Unmarshal([]byte(swapMsgsJson), &swapMsgs) + orderMap, xToY, yToX := types.MakeOrderMap(swapMsgs, DenomX, DenomY, onlyNotMatched) + require.NotZero(t, len(orderMap)) + require.NotNil(t, xToY) + require.NotNil(t, yToX) + + // ErrInvalidDenom case + require.Panics(t, func() { + types.MakeOrderMap(swapMsgs, "12421miklfdjnfiasdjfidosa8381813818---", DenomY, onlyNotMatched) + }) +} + +func TestOrderbookValidate(t *testing.T) { + for _, testCase := range []struct { + currentPrice string + buyPrice string + sellPrice string + valid bool + }{ + { + currentPrice: "1.0", + buyPrice: "0.99", + sellPrice: "1.01", + valid: true, + }, + { + // maxBuyOrderPrice > minSellOrderPrice + currentPrice: "1.0", + buyPrice: "1.01", + sellPrice: "0.99", + valid: false, + }, + { + currentPrice: "1.0", + buyPrice: "1.1", + sellPrice: "1.2", + valid: true, + }, + { + // maxBuyOrderPrice/currentPrice > 1.10 + currentPrice: "1.0", + buyPrice: "1.11", + sellPrice: "1.2", + valid: false, + }, + { + currentPrice: "1.0", + buyPrice: "0.8", + sellPrice: "0.9", + valid: true, + }, + { + // minSellOrderPrice/currentPrice < 0.90 + currentPrice: "1.0", + buyPrice: "0.8", + sellPrice: "0.89", + valid: false, + }, + { + // not positive price + currentPrice: "0.0", + buyPrice: "0.00000000001", + sellPrice: "0.000000000011", + valid: false, + }, + } { + buyPrice := sdk.MustNewDecFromStr(testCase.buyPrice) + sellPrice := sdk.MustNewDecFromStr(testCase.sellPrice) + orderMap := types.OrderMap{ + buyPrice.String(): { + Price: buyPrice, + BuyOfferAmt: sdk.OneInt(), + SellOfferAmt: sdk.ZeroInt(), + }, + sellPrice.String(): { + Price: sellPrice, + BuyOfferAmt: sdk.ZeroInt(), + SellOfferAmt: sdk.OneInt(), + }, + } + orderBook := orderMap.SortOrderBook() + require.Equal(t, testCase.valid, orderBook.Validate(sdk.MustNewDecFromStr(testCase.currentPrice))) + } +} + +func TestCountNotMatchedMsgs(t *testing.T) { + for _, tc := range []struct { + msgs []*types.SwapMsgState + cnt int + }{ + { + []*types.SwapMsgState{}, + 0, + }, + { + []*types.SwapMsgState{ + {Executed: true, Succeeded: false}, + {Executed: true, Succeeded: false}, + }, + 2, + }, + { + []*types.SwapMsgState{ + {}, + {Executed: true, Succeeded: true, ToBeDeleted: false}, + {Executed: true, Succeeded: true, ToBeDeleted: true}, + }, + 0, + }, + } { + require.Equal(t, tc.cnt, types.CountNotMatchedMsgs(tc.msgs)) + } +} + +func TestCountFractionalMatchedMsgs(t *testing.T) { + for _, tc := range []struct { + msgs []*types.SwapMsgState + cnt int + }{ + { + []*types.SwapMsgState{}, + 0, + }, + { + []*types.SwapMsgState{ + {Executed: true, Succeeded: true, ToBeDeleted: false}, + {Executed: true, Succeeded: true, ToBeDeleted: false}, + }, + 2, + }, + { + []*types.SwapMsgState{ + {}, + {Executed: true, Succeeded: false}, + {Executed: true, Succeeded: true, ToBeDeleted: true}, + }, + 0, + }, + } { + require.Equal(t, tc.cnt, types.CountFractionalMatchedMsgs(tc.msgs)) + } +} diff --git a/x/liquidity/types/tx.pb.go b/x/liquidity/types/tx.pb.go new file mode 100644 index 00000000000..bf415f3f73b --- /dev/null +++ b/x/liquidity/types/tx.pb.go @@ -0,0 +1,2069 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tendermint/liquidity/v1beta1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + 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 + +// MsgCreatePool defines an sdk.Msg type that supports submitting a create liquidity pool tx. +// +// See: https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md +type MsgCreatePool struct { + PoolCreatorAddress string `protobuf:"bytes,1,opt,name=pool_creator_address,json=poolCreatorAddress,proto3" json:"pool_creator_address,omitempty" yaml:"pool_creator_address"` + // id of the target pool type, must match the value in the pool. Only pool-type-id 1 is supported. + PoolTypeId uint32 `protobuf:"varint,2,opt,name=pool_type_id,json=poolTypeId,proto3" json:"pool_type_id,omitempty" yaml:"pool_type_id"` + // reserve coin pair of the pool to deposit. + DepositCoins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=deposit_coins,json=depositCoins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"deposit_coins" yaml:"deposit_coins"` +} + +func (m *MsgCreatePool) Reset() { *m = MsgCreatePool{} } +func (m *MsgCreatePool) String() string { return proto.CompactTextString(m) } +func (*MsgCreatePool) ProtoMessage() {} +func (*MsgCreatePool) Descriptor() ([]byte, []int) { + return fileDescriptor_deae1e5d4eb3529c, []int{0} +} +func (m *MsgCreatePool) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreatePool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreatePool.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 *MsgCreatePool) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreatePool.Merge(m, src) +} +func (m *MsgCreatePool) XXX_Size() int { + return m.Size() +} +func (m *MsgCreatePool) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreatePool.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreatePool proto.InternalMessageInfo + +// MsgCreatePoolResponse defines the Msg/CreatePool response type. +type MsgCreatePoolResponse struct { +} + +func (m *MsgCreatePoolResponse) Reset() { *m = MsgCreatePoolResponse{} } +func (m *MsgCreatePoolResponse) String() string { return proto.CompactTextString(m) } +func (*MsgCreatePoolResponse) ProtoMessage() {} +func (*MsgCreatePoolResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_deae1e5d4eb3529c, []int{1} +} +func (m *MsgCreatePoolResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreatePoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreatePoolResponse.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 *MsgCreatePoolResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreatePoolResponse.Merge(m, src) +} +func (m *MsgCreatePoolResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgCreatePoolResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreatePoolResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreatePoolResponse proto.InternalMessageInfo + +// `MsgDepositWithinBatch defines` an `sdk.Msg` type that supports submitting +// a deposit request to the batch of the liquidity pool. +// Deposit is submitted to the batch of the Liquidity pool with the specified +// `pool_id`, `deposit_coins` for reserve. +// This request is stacked in the batch of the liquidity pool, is not processed +// immediately, and is processed in the `endblock` at the same time as other requests. +// +// See: https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md +type MsgDepositWithinBatch struct { + DepositorAddress string `protobuf:"bytes,1,opt,name=depositor_address,json=depositorAddress,proto3" json:"depositor_address,omitempty" yaml:"depositor_address"` + // id of the target pool + PoolId uint64 `protobuf:"varint,2,opt,name=pool_id,json=poolId,proto3" json:"pool_id" yaml:"pool_id"` + // reserve coin pair of the pool to deposit + DepositCoins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=deposit_coins,json=depositCoins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"deposit_coins" yaml:"deposit_coins"` +} + +func (m *MsgDepositWithinBatch) Reset() { *m = MsgDepositWithinBatch{} } +func (m *MsgDepositWithinBatch) String() string { return proto.CompactTextString(m) } +func (*MsgDepositWithinBatch) ProtoMessage() {} +func (*MsgDepositWithinBatch) Descriptor() ([]byte, []int) { + return fileDescriptor_deae1e5d4eb3529c, []int{2} +} +func (m *MsgDepositWithinBatch) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDepositWithinBatch) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDepositWithinBatch.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 *MsgDepositWithinBatch) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDepositWithinBatch.Merge(m, src) +} +func (m *MsgDepositWithinBatch) XXX_Size() int { + return m.Size() +} +func (m *MsgDepositWithinBatch) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDepositWithinBatch.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDepositWithinBatch proto.InternalMessageInfo + +// MsgDepositWithinBatchResponse defines the Msg/DepositWithinBatch response type. +type MsgDepositWithinBatchResponse struct { +} + +func (m *MsgDepositWithinBatchResponse) Reset() { *m = MsgDepositWithinBatchResponse{} } +func (m *MsgDepositWithinBatchResponse) String() string { return proto.CompactTextString(m) } +func (*MsgDepositWithinBatchResponse) ProtoMessage() {} +func (*MsgDepositWithinBatchResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_deae1e5d4eb3529c, []int{3} +} +func (m *MsgDepositWithinBatchResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDepositWithinBatchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDepositWithinBatchResponse.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 *MsgDepositWithinBatchResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDepositWithinBatchResponse.Merge(m, src) +} +func (m *MsgDepositWithinBatchResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgDepositWithinBatchResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDepositWithinBatchResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDepositWithinBatchResponse proto.InternalMessageInfo + +// `MsgWithdrawWithinBatch` defines an `sdk.Msg` type that supports submitting +// a withdraw request to the batch of the liquidity pool. +// Withdraw is submitted to the batch from the Liquidity pool with the +// specified `pool_id`, `pool_coin` of the pool. +// This request is stacked in the batch of the liquidity pool, is not processed +// immediately, and is processed in the `endblock` at the same time as other requests. +// +// See: https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md +type MsgWithdrawWithinBatch struct { + WithdrawerAddress string `protobuf:"bytes,1,opt,name=withdrawer_address,json=withdrawerAddress,proto3" json:"withdrawer_address,omitempty" yaml:"withdrawer_address"` + // id of the target pool + PoolId uint64 `protobuf:"varint,2,opt,name=pool_id,json=poolId,proto3" json:"pool_id" yaml:"pool_id"` + PoolCoin types.Coin `protobuf:"bytes,3,opt,name=pool_coin,json=poolCoin,proto3" json:"pool_coin" yaml:"pool_coin"` +} + +func (m *MsgWithdrawWithinBatch) Reset() { *m = MsgWithdrawWithinBatch{} } +func (m *MsgWithdrawWithinBatch) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawWithinBatch) ProtoMessage() {} +func (*MsgWithdrawWithinBatch) Descriptor() ([]byte, []int) { + return fileDescriptor_deae1e5d4eb3529c, []int{4} +} +func (m *MsgWithdrawWithinBatch) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawWithinBatch) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawWithinBatch.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 *MsgWithdrawWithinBatch) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawWithinBatch.Merge(m, src) +} +func (m *MsgWithdrawWithinBatch) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawWithinBatch) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawWithinBatch.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawWithinBatch proto.InternalMessageInfo + +// MsgWithdrawWithinBatchResponse defines the Msg/WithdrawWithinBatch response type. +type MsgWithdrawWithinBatchResponse struct { +} + +func (m *MsgWithdrawWithinBatchResponse) Reset() { *m = MsgWithdrawWithinBatchResponse{} } +func (m *MsgWithdrawWithinBatchResponse) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawWithinBatchResponse) ProtoMessage() {} +func (*MsgWithdrawWithinBatchResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_deae1e5d4eb3529c, []int{5} +} +func (m *MsgWithdrawWithinBatchResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawWithinBatchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawWithinBatchResponse.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 *MsgWithdrawWithinBatchResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawWithinBatchResponse.Merge(m, src) +} +func (m *MsgWithdrawWithinBatchResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawWithinBatchResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawWithinBatchResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawWithinBatchResponse proto.InternalMessageInfo + +// `MsgSwapWithinBatch` defines an sdk.Msg type that supports submitting a swap offer request to the batch of the liquidity pool. +// Submit swap offer to the liquidity pool batch with the specified the `pool_id`, `swap_type_id`, +// `demand_coin_denom` with the coin and the price you're offering +// and `offer_coin_fee` must be half of offer coin amount * current `params.swap_fee_rate` and ceil for reservation to pay fees. +// This request is stacked in the batch of the liquidity pool, is not processed +// immediately, and is processed in the `endblock` at the same time as other requests. +// You must request the same fields as the pool. +// Only the default `swap_type_id` 1 is supported. +// +// See: https://github.com/cosmos/gaia/v9/tree/develop/doc +// https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md +type MsgSwapWithinBatch struct { + // address of swap requester + SwapRequesterAddress string `protobuf:"bytes,1,opt,name=swap_requester_address,json=swapRequesterAddress,proto3" json:"swap_requester_address,omitempty" yaml:"swap_requester_address"` + // id of swap type, must match the value in the pool. Only `swap_type_id` 1 is supported. + PoolId uint64 `protobuf:"varint,2,opt,name=pool_id,json=poolId,proto3" json:"pool_id" yaml:"pool_id"` + // id of swap type. Must match the value in the pool. + SwapTypeId uint32 `protobuf:"varint,3,opt,name=swap_type_id,json=swapTypeId,proto3" json:"swap_type_id,omitempty" yaml:"swap_type_id"` + // offer sdk.coin for the swap request, must match the denom in the pool. + OfferCoin types.Coin `protobuf:"bytes,4,opt,name=offer_coin,json=offerCoin,proto3" json:"offer_coin" yaml:"offer_coin"` + // denom of demand coin to be exchanged on the swap request, must match the denom in the pool. + DemandCoinDenom string `protobuf:"bytes,5,opt,name=demand_coin_denom,json=demandCoinDenom,proto3" json:"demand_coin_denom,omitempty" yaml:"demand_coin_denom"` + // half of offer coin amount * params.swap_fee_rate and ceil for reservation to pay fees. + OfferCoinFee types.Coin `protobuf:"bytes,6,opt,name=offer_coin_fee,json=offerCoinFee,proto3" json:"offer_coin_fee" yaml:"offer_coin_fee"` + // limit order price for the order, the price is the exchange ratio of X/Y + // where X is the amount of the first coin and Y is the amount + // of the second coin when their denoms are sorted alphabetically. + OrderPrice github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,7,opt,name=order_price,json=orderPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"order_price" yaml:"order_price"` +} + +func (m *MsgSwapWithinBatch) Reset() { *m = MsgSwapWithinBatch{} } +func (m *MsgSwapWithinBatch) String() string { return proto.CompactTextString(m) } +func (*MsgSwapWithinBatch) ProtoMessage() {} +func (*MsgSwapWithinBatch) Descriptor() ([]byte, []int) { + return fileDescriptor_deae1e5d4eb3529c, []int{6} +} +func (m *MsgSwapWithinBatch) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSwapWithinBatch) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSwapWithinBatch.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 *MsgSwapWithinBatch) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSwapWithinBatch.Merge(m, src) +} +func (m *MsgSwapWithinBatch) XXX_Size() int { + return m.Size() +} +func (m *MsgSwapWithinBatch) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSwapWithinBatch.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSwapWithinBatch proto.InternalMessageInfo + +// MsgSwapWithinBatchResponse defines the Msg/Swap response type. +type MsgSwapWithinBatchResponse struct { +} + +func (m *MsgSwapWithinBatchResponse) Reset() { *m = MsgSwapWithinBatchResponse{} } +func (m *MsgSwapWithinBatchResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSwapWithinBatchResponse) ProtoMessage() {} +func (*MsgSwapWithinBatchResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_deae1e5d4eb3529c, []int{7} +} +func (m *MsgSwapWithinBatchResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSwapWithinBatchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSwapWithinBatchResponse.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 *MsgSwapWithinBatchResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSwapWithinBatchResponse.Merge(m, src) +} +func (m *MsgSwapWithinBatchResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSwapWithinBatchResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSwapWithinBatchResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSwapWithinBatchResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgCreatePool)(nil), "tendermint.liquidity.v1beta1.MsgCreatePool") + proto.RegisterType((*MsgCreatePoolResponse)(nil), "tendermint.liquidity.v1beta1.MsgCreatePoolResponse") + proto.RegisterType((*MsgDepositWithinBatch)(nil), "tendermint.liquidity.v1beta1.MsgDepositWithinBatch") + proto.RegisterType((*MsgDepositWithinBatchResponse)(nil), "tendermint.liquidity.v1beta1.MsgDepositWithinBatchResponse") + proto.RegisterType((*MsgWithdrawWithinBatch)(nil), "tendermint.liquidity.v1beta1.MsgWithdrawWithinBatch") + proto.RegisterType((*MsgWithdrawWithinBatchResponse)(nil), "tendermint.liquidity.v1beta1.MsgWithdrawWithinBatchResponse") + proto.RegisterType((*MsgSwapWithinBatch)(nil), "tendermint.liquidity.v1beta1.MsgSwapWithinBatch") + proto.RegisterType((*MsgSwapWithinBatchResponse)(nil), "tendermint.liquidity.v1beta1.MsgSwapWithinBatchResponse") +} + +func init() { + proto.RegisterFile("tendermint/liquidity/v1beta1/tx.proto", fileDescriptor_deae1e5d4eb3529c) +} + +var fileDescriptor_deae1e5d4eb3529c = []byte{ + // 1161 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x97, 0xcf, 0x6f, 0xdb, 0x54, + 0x1c, 0xc0, 0xe3, 0x26, 0xeb, 0x8f, 0xb7, 0xb6, 0xac, 0x5e, 0xb7, 0x65, 0x61, 0x8b, 0xad, 0x27, + 0x0d, 0x05, 0xb1, 0x3a, 0x89, 0x9d, 0xb4, 0x4d, 0xe1, 0xe2, 0x24, 0x2d, 0x22, 0x52, 0xa5, 0x61, + 0x86, 0x18, 0x20, 0x14, 0xb9, 0xf6, 0x6b, 0x6a, 0x96, 0xbc, 0xe7, 0xfa, 0x39, 0x6d, 0x03, 0xda, + 0x15, 0x81, 0x76, 0x19, 0x99, 0xb8, 0x21, 0x31, 0xf5, 0x88, 0xc4, 0xbf, 0x80, 0x84, 0x84, 0xd0, + 0x0e, 0x1c, 0x76, 0x44, 0x1c, 0x02, 0x6a, 0x2f, 0x88, 0x03, 0x87, 0x1e, 0x10, 0x27, 0x84, 0x9e, + 0xed, 0xa4, 0x6e, 0x12, 0x96, 0x6d, 0x9a, 0xd4, 0xc3, 0x72, 0xc9, 0x7b, 0xdf, 0xdf, 0xdf, 0xf7, + 0x3e, 0x7e, 0xcf, 0x06, 0xd7, 0x5c, 0x84, 0x4d, 0xe4, 0x34, 0x2c, 0xec, 0xa6, 0xeb, 0xd6, 0x76, + 0xd3, 0x32, 0x2d, 0xb7, 0x95, 0xde, 0xc9, 0x6e, 0x20, 0x57, 0xcf, 0xa6, 0xdd, 0x3d, 0xc9, 0x76, + 0x88, 0x4b, 0xf8, 0x2b, 0xc7, 0x66, 0x52, 0xcf, 0x4c, 0x0a, 0xcc, 0x12, 0xf3, 0x35, 0x52, 0x23, + 0x9e, 0x61, 0x9a, 0x8d, 0x7c, 0x9f, 0xc4, 0x25, 0x83, 0xd0, 0x06, 0xa1, 0x55, 0x5f, 0x61, 0x10, + 0x0b, 0x07, 0x0a, 0xff, 0xcf, 0x58, 0xa8, 0x21, 0xbc, 0x40, 0x6c, 0x84, 0x75, 0xdb, 0xda, 0x91, + 0xd3, 0xc4, 0x76, 0x2d, 0x82, 0x69, 0x5a, 0xc7, 0x98, 0xb8, 0xba, 0x37, 0xf6, 0x0d, 0xe1, 0x37, + 0x31, 0x30, 0xb3, 0x4e, 0x6b, 0x25, 0x07, 0xe9, 0x2e, 0xba, 0x41, 0x48, 0x9d, 0xff, 0x89, 0x03, + 0xf3, 0x36, 0x21, 0xf5, 0xaa, 0xc1, 0x64, 0xc4, 0xa9, 0xea, 0xa6, 0xe9, 0x20, 0x4a, 0xe3, 0x9c, + 0xc8, 0xa5, 0xa6, 0x8a, 0xf7, 0xb9, 0xb6, 0xba, 0x2d, 0x2f, 0xe8, 0x86, 0x41, 0x9a, 0xd8, 0x15, + 0x03, 0xa5, 0x48, 0x36, 0x45, 0x77, 0x0b, 0x89, 0xc4, 0xb1, 0x6a, 0x16, 0xf6, 0x67, 0x16, 0x15, + 0x1b, 0x88, 0x52, 0xbd, 0x86, 0x2a, 0x69, 0xe8, 0xd7, 0x9b, 0x45, 0x4a, 0xbe, 0xb5, 0x58, 0x70, + 0xb6, 0x1c, 0x77, 0xa9, 0x95, 0x6b, 0x19, 0x28, 0x5f, 0xcf, 0x37, 0x97, 0x14, 0xfa, 0x31, 0xde, + 0x6b, 0x66, 0xea, 0x8a, 0xb2, 0xbb, 0xf3, 0x09, 0x6e, 0x35, 0x31, 0xdc, 0x1f, 0x9b, 0xa5, 0xe6, + 0x6d, 0x49, 0x35, 0x0c, 0xd5, 0x8f, 0x7f, 0xd4, 0x11, 0x5e, 0x6e, 0xe9, 0x8d, 0xfa, 0x0a, 0x1c, + 0x56, 0x1a, 0xd4, 0x78, 0x26, 0x2e, 0xf9, 0xd2, 0xc0, 0x85, 0xaf, 0x80, 0x69, 0xcf, 0xd8, 0x6d, + 0xd9, 0xa8, 0x6a, 0x99, 0xf1, 0x31, 0x91, 0x4b, 0xcd, 0x14, 0x53, 0x6d, 0x75, 0xb6, 0x12, 0x85, + 0x59, 0xb8, 0x3f, 0x36, 0xde, 0xb4, 0xb0, 0xab, 0xc8, 0x47, 0x1d, 0xe1, 0x7c, 0x28, 0x76, 0x60, + 0x0e, 0x35, 0xc0, 0xa6, 0x37, 0x5b, 0x36, 0x7a, 0xcb, 0xe4, 0xff, 0xe2, 0xc0, 0x8c, 0x89, 0x6c, + 0x42, 0x2d, 0xb7, 0xca, 0x56, 0x9b, 0xc6, 0x63, 0x62, 0x34, 0x75, 0x56, 0xbe, 0x2c, 0xf9, 0x8d, + 0x49, 0x1b, 0x3a, 0x45, 0xdd, 0x3d, 0x93, 0x4a, 0xc4, 0xc2, 0xc5, 0xef, 0xb8, 0xb6, 0xba, 0x51, + 0xb9, 0xf9, 0xe1, 0xa7, 0xd0, 0x44, 0x98, 0x34, 0xe0, 0x8a, 0xe8, 0x0f, 0x6e, 0xc1, 0xeb, 0x22, + 0xd4, 0x1b, 0x6c, 0xf5, 0x98, 0x2c, 0x9b, 0xf1, 0x7e, 0xf0, 0xce, 0x75, 0xb1, 0xdf, 0xf2, 0xfd, + 0x93, 0x96, 0x72, 0xd7, 0xf2, 0xa3, 0xfd, 0xb1, 0x29, 0xb6, 0x3c, 0x2c, 0x0d, 0x7d, 0xd8, 0x11, + 0x22, 0x47, 0x1d, 0x61, 0xde, 0xef, 0xe0, 0x44, 0x8d, 0xf0, 0xdb, 0xdf, 0x84, 0x54, 0xcd, 0x72, + 0xb7, 0x9a, 0x1b, 0x92, 0x41, 0x1a, 0x69, 0xbf, 0xd4, 0xe0, 0x6f, 0x81, 0x9a, 0xb7, 0xd3, 0xac, + 0x57, 0xea, 0xc7, 0xd1, 0xa6, 0x03, 0x5f, 0x6f, 0xb6, 0x32, 0xf9, 0xf9, 0x03, 0x21, 0xf2, 0xc7, + 0x03, 0x21, 0x02, 0x2f, 0x81, 0x0b, 0x27, 0x00, 0xd1, 0x10, 0xb5, 0x09, 0xa6, 0x08, 0x7e, 0x1d, + 0xf3, 0x34, 0x65, 0xdf, 0xed, 0x3d, 0xcb, 0xdd, 0xb2, 0x70, 0x51, 0x77, 0x8d, 0x2d, 0xfe, 0x7b, + 0x0e, 0xcc, 0x05, 0xd1, 0x06, 0xf8, 0xb9, 0x77, 0x5a, 0xfc, 0xc4, 0x4f, 0xac, 0x50, 0x18, 0x9e, + 0x73, 0x3d, 0x59, 0x17, 0x9d, 0x37, 0xc1, 0x84, 0xc7, 0x42, 0x40, 0x4d, 0xac, 0x28, 0xf5, 0x51, + 0xb3, 0x98, 0xfb, 0xb3, 0x23, 0x74, 0x6d, 0x8e, 0x3a, 0xc2, 0x6c, 0x08, 0x20, 0xc6, 0xce, 0x38, + 0x1b, 0x0d, 0xe5, 0x26, 0xfa, 0xa2, 0x70, 0x23, 0x80, 0xab, 0x43, 0xe9, 0xe8, 0xf1, 0xf3, 0x77, + 0x14, 0x5c, 0x5c, 0xa7, 0x35, 0xa6, 0x32, 0x1d, 0x7d, 0x37, 0x0c, 0xd0, 0x0f, 0x1c, 0xe0, 0x77, + 0x03, 0x39, 0xea, 0x27, 0xe8, 0xcb, 0xd3, 0x22, 0xe8, 0xb2, 0xbf, 0x56, 0x83, 0x85, 0x41, 0x6d, + 0xee, 0x58, 0xf8, 0xdc, 0x19, 0xfa, 0x91, 0x03, 0x53, 0xfe, 0xa9, 0x47, 0x2c, 0x1c, 0x8f, 0x8a, + 0xdc, 0xe3, 0xf9, 0xb9, 0xcb, 0xb5, 0x55, 0xbb, 0x62, 0x84, 0xa0, 0x60, 0xce, 0x65, 0x25, 0xaf, + 0x66, 0x4a, 0xa5, 0xec, 0xe2, 0xea, 0x6a, 0xbe, 0xb0, 0xbc, 0x56, 0xc8, 0x14, 0x33, 0xb9, 0x5c, + 0x69, 0x55, 0x2e, 0x2c, 0xaa, 0xb9, 0x4c, 0xbe, 0xa8, 0x16, 0x4a, 0xca, 0x72, 0x76, 0x55, 0x59, + 0x5e, 0x56, 0x96, 0xf2, 0x85, 0x42, 0xb9, 0xb0, 0xb8, 0x26, 0xaf, 0x2d, 0x65, 0x4a, 0xf2, 0x5a, + 0x46, 0x56, 0x65, 0x45, 0xcd, 0x0d, 0xc2, 0x07, 0xef, 0xec, 0x8f, 0x4d, 0x76, 0x71, 0x0a, 0x68, + 0x3a, 0x17, 0x3e, 0xa3, 0x89, 0x85, 0xa1, 0x36, 0xe9, 0x1d, 0xcc, 0xc4, 0xc2, 0x21, 0x32, 0x44, + 0x90, 0x1c, 0xbe, 0xef, 0x3d, 0x34, 0xfe, 0x19, 0x07, 0xfc, 0x3a, 0xad, 0xbd, 0xb3, 0xab, 0xdb, + 0x61, 0x2c, 0x7e, 0xe6, 0xc0, 0x45, 0xba, 0xab, 0xdb, 0x55, 0x07, 0x6d, 0x37, 0x11, 0x75, 0x07, + 0xd0, 0xf8, 0xea, 0xb4, 0xd0, 0xb8, 0xea, 0x37, 0x3e, 0xbc, 0x38, 0xa8, 0xcd, 0x33, 0x85, 0xd6, + 0x95, 0x3f, 0x77, 0x42, 0x2a, 0x60, 0xda, 0xcb, 0xdc, 0xbd, 0xe9, 0xa2, 0x23, 0x6f, 0xba, 0xb0, + 0x39, 0xd4, 0x00, 0x9b, 0x06, 0x37, 0xdd, 0x5d, 0x0e, 0x00, 0xb2, 0xb9, 0x89, 0x1c, 0x1f, 0xb7, + 0xd8, 0x28, 0xdc, 0xde, 0x6e, 0xab, 0xf9, 0x4a, 0xea, 0x49, 0x0f, 0xab, 0x41, 0x64, 0xe6, 0xfc, + 0x82, 0x8e, 0x53, 0x42, 0x6d, 0xca, 0x9b, 0x30, 0x1b, 0xfe, 0x5d, 0x76, 0x91, 0x34, 0x74, 0x6c, + 0x7a, 0xaa, 0xaa, 0x17, 0x3b, 0x7e, 0xc6, 0xdb, 0xeb, 0x57, 0xdb, 0x2a, 0xa8, 0x4c, 0xfa, 0xe9, + 0x8a, 0x30, 0x7c, 0xc0, 0xf7, 0xd9, 0x43, 0xed, 0x25, 0x5f, 0xc6, 0x22, 0x96, 0x99, 0x84, 0xbf, + 0xcf, 0x81, 0xd9, 0xe3, 0x8c, 0xd5, 0x4d, 0x84, 0xe2, 0xe3, 0xa3, 0x1a, 0xd5, 0xda, 0xaa, 0x5c, + 0xb9, 0x36, 0xa2, 0xd1, 0xfc, 0xff, 0x74, 0x79, 0xa1, 0xbf, 0x4b, 0x96, 0x13, 0x6a, 0xd3, 0xbd, + 0x4e, 0xd7, 0x10, 0xe2, 0x5b, 0xe0, 0x2c, 0x71, 0x4c, 0xe4, 0x54, 0x6d, 0xc7, 0x32, 0x50, 0x7c, + 0xc2, 0x6b, 0xf3, 0x56, 0x5b, 0x9d, 0xab, 0x9c, 0x81, 0x59, 0x89, 0xed, 0xe3, 0x04, 0x0b, 0x5b, + 0x46, 0x06, 0x8b, 0xfa, 0x6b, 0x47, 0x78, 0xe5, 0x09, 0x0e, 0xe9, 0x32, 0x32, 0x8e, 0x3a, 0x02, + 0x1f, 0xe4, 0x3f, 0x0e, 0x0f, 0x35, 0xe0, 0xcd, 0x6e, 0xb0, 0x49, 0xe8, 0xe1, 0xbc, 0x02, 0x12, + 0x83, 0x4f, 0x5e, 0xf7, 0xc1, 0x94, 0xff, 0x8d, 0x82, 0xe8, 0x3a, 0xad, 0xf1, 0x18, 0x80, 0xd0, + 0x2b, 0xe3, 0x6b, 0xd2, 0xe3, 0x5e, 0x61, 0xa5, 0x13, 0xaf, 0x0f, 0x09, 0xe5, 0x29, 0x8c, 0xbb, + 0x79, 0xf9, 0xcf, 0x38, 0xc0, 0x0f, 0x79, 0xd1, 0x18, 0x1d, 0x6b, 0xd0, 0x29, 0xf1, 0xfa, 0x33, + 0x38, 0xf5, 0x0a, 0xf9, 0x82, 0x03, 0xe7, 0x87, 0xdd, 0x58, 0xb9, 0x91, 0x41, 0x87, 0x78, 0x25, + 0xde, 0x78, 0x16, 0xaf, 0x5e, 0x2d, 0x0e, 0x88, 0xb1, 0x7d, 0xe2, 0x33, 0x23, 0xa3, 0xf4, 0x6d, + 0x67, 0x62, 0xf9, 0x69, 0x3d, 0xba, 0x39, 0x8b, 0xeb, 0x0f, 0x0f, 0x92, 0xdc, 0xa3, 0x83, 0x24, + 0xf7, 0xfb, 0x41, 0x92, 0xbb, 0x77, 0x98, 0x8c, 0x3c, 0x3a, 0x4c, 0x46, 0x7e, 0x39, 0x4c, 0x46, + 0x3e, 0x50, 0x42, 0x30, 0xd6, 0x1c, 0x7d, 0xc7, 0x72, 0x5b, 0x0b, 0x26, 0xda, 0xa1, 0xa1, 0x4f, + 0x9f, 0xbd, 0xd0, 0xd8, 0xa3, 0x73, 0x63, 0xdc, 0xfb, 0x0a, 0x51, 0xfe, 0x0b, 0x00, 0x00, 0xff, + 0xff, 0x43, 0x80, 0x9a, 0x7c, 0x2b, 0x0d, 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 { + // Submit a create liquidity pool message. + CreatePool(ctx context.Context, in *MsgCreatePool, opts ...grpc.CallOption) (*MsgCreatePoolResponse, error) + // Submit a deposit to the liquidity pool batch. + DepositWithinBatch(ctx context.Context, in *MsgDepositWithinBatch, opts ...grpc.CallOption) (*MsgDepositWithinBatchResponse, error) + // Submit a withdraw from the liquidity pool batch. + WithdrawWithinBatch(ctx context.Context, in *MsgWithdrawWithinBatch, opts ...grpc.CallOption) (*MsgWithdrawWithinBatchResponse, error) + // Submit a swap to the liquidity pool batch. + Swap(ctx context.Context, in *MsgSwapWithinBatch, opts ...grpc.CallOption) (*MsgSwapWithinBatchResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) CreatePool(ctx context.Context, in *MsgCreatePool, opts ...grpc.CallOption) (*MsgCreatePoolResponse, error) { + out := new(MsgCreatePoolResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Msg/CreatePool", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) DepositWithinBatch(ctx context.Context, in *MsgDepositWithinBatch, opts ...grpc.CallOption) (*MsgDepositWithinBatchResponse, error) { + out := new(MsgDepositWithinBatchResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Msg/DepositWithinBatch", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) WithdrawWithinBatch(ctx context.Context, in *MsgWithdrawWithinBatch, opts ...grpc.CallOption) (*MsgWithdrawWithinBatchResponse, error) { + out := new(MsgWithdrawWithinBatchResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Msg/WithdrawWithinBatch", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Swap(ctx context.Context, in *MsgSwapWithinBatch, opts ...grpc.CallOption) (*MsgSwapWithinBatchResponse, error) { + out := new(MsgSwapWithinBatchResponse) + err := c.cc.Invoke(ctx, "/tendermint.liquidity.v1beta1.Msg/Swap", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // Submit a create liquidity pool message. + CreatePool(context.Context, *MsgCreatePool) (*MsgCreatePoolResponse, error) + // Submit a deposit to the liquidity pool batch. + DepositWithinBatch(context.Context, *MsgDepositWithinBatch) (*MsgDepositWithinBatchResponse, error) + // Submit a withdraw from the liquidity pool batch. + WithdrawWithinBatch(context.Context, *MsgWithdrawWithinBatch) (*MsgWithdrawWithinBatchResponse, error) + // Submit a swap to the liquidity pool batch. + Swap(context.Context, *MsgSwapWithinBatch) (*MsgSwapWithinBatchResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) CreatePool(ctx context.Context, req *MsgCreatePool) (*MsgCreatePoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreatePool not implemented") +} +func (*UnimplementedMsgServer) DepositWithinBatch(ctx context.Context, req *MsgDepositWithinBatch) (*MsgDepositWithinBatchResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DepositWithinBatch not implemented") +} +func (*UnimplementedMsgServer) WithdrawWithinBatch(ctx context.Context, req *MsgWithdrawWithinBatch) (*MsgWithdrawWithinBatchResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method WithdrawWithinBatch not implemented") +} +func (*UnimplementedMsgServer) Swap(ctx context.Context, req *MsgSwapWithinBatch) (*MsgSwapWithinBatchResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Swap not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_CreatePool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgCreatePool) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).CreatePool(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Msg/CreatePool", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).CreatePool(ctx, req.(*MsgCreatePool)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_DepositWithinBatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgDepositWithinBatch) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).DepositWithinBatch(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Msg/DepositWithinBatch", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).DepositWithinBatch(ctx, req.(*MsgDepositWithinBatch)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_WithdrawWithinBatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgWithdrawWithinBatch) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).WithdrawWithinBatch(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Msg/WithdrawWithinBatch", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).WithdrawWithinBatch(ctx, req.(*MsgWithdrawWithinBatch)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Swap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSwapWithinBatch) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Swap(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.liquidity.v1beta1.Msg/Swap", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Swap(ctx, req.(*MsgSwapWithinBatch)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "tendermint.liquidity.v1beta1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreatePool", + Handler: _Msg_CreatePool_Handler, + }, + { + MethodName: "DepositWithinBatch", + Handler: _Msg_DepositWithinBatch_Handler, + }, + { + MethodName: "WithdrawWithinBatch", + Handler: _Msg_WithdrawWithinBatch_Handler, + }, + { + MethodName: "Swap", + Handler: _Msg_Swap_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "tendermint/liquidity/v1beta1/tx.proto", +} + +func (m *MsgCreatePool) 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 *MsgCreatePool) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreatePool) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.DepositCoins) > 0 { + for iNdEx := len(m.DepositCoins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DepositCoins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if m.PoolTypeId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PoolTypeId)) + i-- + dAtA[i] = 0x10 + } + if len(m.PoolCreatorAddress) > 0 { + i -= len(m.PoolCreatorAddress) + copy(dAtA[i:], m.PoolCreatorAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.PoolCreatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgCreatePoolResponse) 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 *MsgCreatePoolResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreatePoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgDepositWithinBatch) 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 *MsgDepositWithinBatch) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDepositWithinBatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.DepositCoins) > 0 { + for iNdEx := len(m.DepositCoins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DepositCoins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.PoolId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x10 + } + if len(m.DepositorAddress) > 0 { + i -= len(m.DepositorAddress) + copy(dAtA[i:], m.DepositorAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.DepositorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgDepositWithinBatchResponse) 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 *MsgDepositWithinBatchResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDepositWithinBatchResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawWithinBatch) 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 *MsgWithdrawWithinBatch) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawWithinBatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.PoolCoin.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.PoolId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x10 + } + if len(m.WithdrawerAddress) > 0 { + i -= len(m.WithdrawerAddress) + copy(dAtA[i:], m.WithdrawerAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.WithdrawerAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawWithinBatchResponse) 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 *MsgWithdrawWithinBatchResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawWithinBatchResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgSwapWithinBatch) 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 *MsgSwapWithinBatch) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSwapWithinBatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.OrderPrice.Size() + i -= size + if _, err := m.OrderPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + { + size, err := m.OfferCoinFee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.DemandCoinDenom) > 0 { + i -= len(m.DemandCoinDenom) + copy(dAtA[i:], m.DemandCoinDenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.DemandCoinDenom))) + i-- + dAtA[i] = 0x2a + } + { + size, err := m.OfferCoin.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if m.SwapTypeId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.SwapTypeId)) + i-- + dAtA[i] = 0x18 + } + if m.PoolId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x10 + } + if len(m.SwapRequesterAddress) > 0 { + i -= len(m.SwapRequesterAddress) + copy(dAtA[i:], m.SwapRequesterAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.SwapRequesterAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSwapWithinBatchResponse) 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 *MsgSwapWithinBatchResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSwapWithinBatchResponse) 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 *MsgCreatePool) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PoolCreatorAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PoolTypeId != 0 { + n += 1 + sovTx(uint64(m.PoolTypeId)) + } + if len(m.DepositCoins) > 0 { + for _, e := range m.DepositCoins { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgCreatePoolResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgDepositWithinBatch) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DepositorAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PoolId != 0 { + n += 1 + sovTx(uint64(m.PoolId)) + } + if len(m.DepositCoins) > 0 { + for _, e := range m.DepositCoins { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgDepositWithinBatchResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgWithdrawWithinBatch) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.WithdrawerAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PoolId != 0 { + n += 1 + sovTx(uint64(m.PoolId)) + } + l = m.PoolCoin.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgWithdrawWithinBatchResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgSwapWithinBatch) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SwapRequesterAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PoolId != 0 { + n += 1 + sovTx(uint64(m.PoolId)) + } + if m.SwapTypeId != 0 { + n += 1 + sovTx(uint64(m.SwapTypeId)) + } + l = m.OfferCoin.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.DemandCoinDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.OfferCoinFee.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.OrderPrice.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgSwapWithinBatchResponse) 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 *MsgCreatePool) 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: MsgCreatePool: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreatePool: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolCreatorAddress", 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.PoolCreatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolTypeId", wireType) + } + m.PoolTypeId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolTypeId |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DepositCoins", 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.DepositCoins = append(m.DepositCoins, types.Coin{}) + if err := m.DepositCoins[len(m.DepositCoins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgCreatePoolResponse) 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: MsgCreatePoolResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreatePoolResponse: 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 *MsgDepositWithinBatch) 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: MsgDepositWithinBatch: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDepositWithinBatch: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DepositorAddress", 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.DepositorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DepositCoins", 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.DepositCoins = append(m.DepositCoins, types.Coin{}) + if err := m.DepositCoins[len(m.DepositCoins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDepositWithinBatchResponse) 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: MsgDepositWithinBatchResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDepositWithinBatchResponse: 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 *MsgWithdrawWithinBatch) 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: MsgWithdrawWithinBatch: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawWithinBatch: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WithdrawerAddress", 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.WithdrawerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolCoin", 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.PoolCoin.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 *MsgWithdrawWithinBatchResponse) 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: MsgWithdrawWithinBatchResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawWithinBatchResponse: 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 *MsgSwapWithinBatch) 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: MsgSwapWithinBatch: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSwapWithinBatch: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SwapRequesterAddress", 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.SwapRequesterAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SwapTypeId", wireType) + } + m.SwapTypeId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SwapTypeId |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OfferCoin", 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.OfferCoin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DemandCoinDenom", 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.DemandCoinDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OfferCoinFee", 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.OfferCoinFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OrderPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.OrderPrice.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 *MsgSwapWithinBatchResponse) 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: MsgSwapWithinBatchResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSwapWithinBatchResponse: 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/liquidity/types/utils.go b/x/liquidity/types/utils.go new file mode 100644 index 00000000000..d8e1fde0cb5 --- /dev/null +++ b/x/liquidity/types/utils.go @@ -0,0 +1,124 @@ +package types + +import ( + "crypto/sha256" + "fmt" + "sort" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + "github.com/tendermint/tendermint/crypto" +) + +// AlphabeticalDenomPair returns denom pairs that are alphabetically sorted. +func AlphabeticalDenomPair(denom1, denom2 string) (resDenom1, resDenom2 string) { + if denom1 > denom2 { + return denom2, denom1 + } + return denom1, denom2 +} + +// SortDenoms sorts denoms in alphabetical order. +func SortDenoms(denoms []string) []string { + sort.Strings(denoms) + return denoms +} + +// GetPoolReserveAcc returns the address of the pool's reserve account. +func GetPoolReserveAcc(poolName string, len32 bool) sdk.AccAddress { + if len32 { + // The rules are temporarily added for testing on 32-length bytes addresses of ADR-28 and are subject to change. + poolCoinDenom := GetPoolCoinDenom(poolName) + poolCoinDenom = strings.TrimPrefix(poolCoinDenom, PoolCoinDenomPrefix) + return sdk.AccAddress(address.Module(ModuleName, []byte(poolCoinDenom))) + } + return sdk.AccAddress(crypto.AddressHash([]byte(poolName))) +} + +// GetPoolCoinDenom returns the denomination of the pool coin. +func GetPoolCoinDenom(poolName string) string { + // Originally pool coin denom has prefix with / splitter, but removed prefix for pass validation of ibc-transfer + return fmt.Sprintf("%s%X", PoolCoinDenomPrefix, sha256.Sum256([]byte(poolName))) +} + +// GetReserveAcc extracts and returns reserve account from pool coin denom. +func GetReserveAcc(poolCoinDenom string, len32 bool) (sdk.AccAddress, error) { + if err := sdk.ValidateDenom(poolCoinDenom); err != nil { + return nil, err + } + if !strings.HasPrefix(poolCoinDenom, PoolCoinDenomPrefix) { + return nil, ErrInvalidDenom + } + poolCoinDenom = strings.TrimPrefix(poolCoinDenom, PoolCoinDenomPrefix) + if len(poolCoinDenom) != 64 { + return nil, ErrInvalidDenom + } + if len32 { + // The rules are temporarily added for testing on 32-length bytes addresses of ADR-28 and are subject to change. + return sdk.AccAddress(address.Module(ModuleName, []byte(poolCoinDenom))), nil + } + return sdk.AccAddressFromHex(poolCoinDenom[:40]) +} + +// GetCoinsTotalAmount returns total amount of all coins in sdk.Coins. +func GetCoinsTotalAmount(coins sdk.Coins) sdk.Int { + totalAmount := sdk.ZeroInt() + for _, coin := range coins { + totalAmount = totalAmount.Add(coin.Amount) + } + return totalAmount +} + +// ValidateReserveCoinLimit checks if total amounts of depositCoins exceed maxReserveCoinAmount. +func ValidateReserveCoinLimit(maxReserveCoinAmount sdk.Int, depositCoins sdk.Coins) error { + totalAmount := GetCoinsTotalAmount(depositCoins) + if maxReserveCoinAmount.IsZero() { + return nil + } else if totalAmount.GT(maxReserveCoinAmount) { + return ErrExceededReserveCoinLimit + } else { + return nil + } +} + +func GetOfferCoinFee(offerCoin sdk.Coin, swapFeeRate sdk.Dec) sdk.Coin { + if swapFeeRate.IsZero() { + return sdk.NewCoin(offerCoin.Denom, sdk.ZeroInt()) + } + // apply half-ratio swap fee rate and ceiling + // see https://github.com/tendermint/liquidity/issues/41 for details + return sdk.NewCoin(offerCoin.Denom, offerCoin.Amount.ToDec().Mul(swapFeeRate.QuoInt64(2)).Ceil().TruncateInt()) // Ceil(offerCoin.Amount * (swapFeeRate/2)) +} + +func MustParseCoinsNormalized(coinStr string) sdk.Coins { + coins, err := sdk.ParseCoinsNormalized(coinStr) + if err != nil { + panic(err) + } + return coins +} + +func CheckOverflow(a, b sdk.Int) (err error) { + defer func() { + if r := recover(); r != nil { + err = ErrOverflowAmount + } + }() + a.Mul(b) + a.Quo(b) + b.Quo(a) + return nil +} + +func CheckOverflowWithDec(a, b sdk.Dec) (err error) { + defer func() { + if r := recover(); r != nil { + err = ErrOverflowAmount + } + }() + a.Mul(b) + a.Quo(b) + b.Quo(a) + return nil +} diff --git a/x/liquidity/types/utils_test.go b/x/liquidity/types/utils_test.go new file mode 100644 index 00000000000..6e9cb95c4c2 --- /dev/null +++ b/x/liquidity/types/utils_test.go @@ -0,0 +1,340 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +func TestAlphabeticalDenomPair(t *testing.T) { + denomA := "uCoinA" + denomB := "uCoinB" + afterDenomA, afterDenomB := types.AlphabeticalDenomPair(denomA, denomB) + require.Equal(t, denomA, afterDenomA) + require.Equal(t, denomB, afterDenomB) + + afterDenomA, afterDenomB = types.AlphabeticalDenomPair(denomB, denomA) + require.Equal(t, denomA, afterDenomA) + require.Equal(t, denomB, afterDenomB) +} + +func TestGetReserveAcc(t *testing.T) { + expectedReserveAcc, _ := sdk.AccAddressFromBech32("cosmos16ddqestwukv0jzcyfn3fdfq9h2wrs83cr4rfm3") + tests := []struct { + poolCoinDenom string + expectedReserveAcc sdk.AccAddress + expPass bool + }{ + { + poolCoinDenom: "poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4", + expectedReserveAcc: expectedReserveAcc, + expPass: true, + }, + { + poolCoinDenom: "poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A", + expectedReserveAcc: nil, + expPass: false, + }, + { + poolCoinDenom: "D35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4", + expectedReserveAcc: nil, + expPass: false, + }, + { + poolCoinDenom: "ibc/D35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4", + expectedReserveAcc: nil, + expPass: false, + }, + } + + for _, tc := range tests { + reserveAcc, err := types.GetReserveAcc(tc.poolCoinDenom, false) + if tc.expPass { + require.Equal(t, tc.expectedReserveAcc, reserveAcc) + } else { + require.Nil(t, reserveAcc) + require.ErrorIs(t, err, types.ErrInvalidDenom) + } + } +} + +func TestSortDenoms(t *testing.T) { + tests := []struct { + denoms []string + expectedDenoms []string + }{ + { + denoms: []string{"uCoinB", "uCoinA"}, + expectedDenoms: []string{"uCoinA", "uCoinB"}, + }, + { + denoms: []string{"uCoinC", "uCoinA", "uCoinB"}, + expectedDenoms: []string{"uCoinA", "uCoinB", "uCoinC"}, + }, + { + denoms: []string{"uCoinC", "uCoinA", "uCoinD", "uCoinB"}, + expectedDenoms: []string{"uCoinA", "uCoinB", "uCoinC", "uCoinD"}, + }, + } + + for _, tc := range tests { + sortedDenoms := types.SortDenoms(tc.denoms) + require.Equal(t, tc.expectedDenoms, sortedDenoms) + } +} + +func TestGetPoolInformation(t *testing.T) { + testCases := []struct { + reserveCoinDenoms []string + poolTypeID uint32 + expectedPoolName string + expectedReserveAcc string + expectedPoolCoinDenom string + len32 bool + }{ + { + reserveCoinDenoms: []string{"denomX", "denomY"}, + poolTypeID: uint32(1), + expectedPoolName: "denomX/denomY/1", + expectedReserveAcc: "cosmos16ddqestwukv0jzcyfn3fdfq9h2wrs83cr4rfm3", + expectedPoolCoinDenom: "poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4", + len32: false, + }, + { + reserveCoinDenoms: []string{"stake", "token"}, + poolTypeID: uint32(1), + expectedPoolName: "stake/token/1", + expectedReserveAcc: "cosmos1unfxz7l7q0s3gmmthgwe3yljk0thhg57ym3p6u", + expectedPoolCoinDenom: "poolE4D2617BFE03E1146F6BBA1D9893F2B3D77BA29E7ED532BB721A39FF1ECC1B07", + len32: false, + }, + { + reserveCoinDenoms: []string{"uatom", "uusd"}, + poolTypeID: uint32(2), + expectedPoolName: "uatom/uusd/2", + expectedReserveAcc: "cosmos1xqm0g09czvdp5c7jk0fmz85u7maz52m040eh8g", + expectedPoolCoinDenom: "pool3036F43CB8131A1A63D2B3D3B11E9CF6FA2A2B6FEC17D5AD283C25C939614A8C", + len32: false, + }, + { + reserveCoinDenoms: []string{"uatom", "usdt"}, + poolTypeID: uint32(3), + expectedPoolName: "uatom/usdt/3", + expectedReserveAcc: "cosmos1aqvez6g6wejw8hu35kplycf2taqsfkpj3ns3c5v4dhwazfdzhzastyr290", + expectedPoolCoinDenom: "pool93E069B333B5ECEBFE24C6E1437E814003248E0DD7FF8B9F82119F4587449BA5", + len32: true, + }, + } + + for _, tc := range testCases { + poolName := types.PoolName(tc.reserveCoinDenoms, tc.poolTypeID) + require.Equal(t, tc.expectedPoolName, poolName) + + reserveAcc := types.GetPoolReserveAcc(poolName, tc.len32) + require.Equal(t, tc.expectedReserveAcc, reserveAcc.String()) + + poolCoinDenom := types.GetPoolCoinDenom(poolName) + require.Equal(t, tc.expectedPoolCoinDenom, poolCoinDenom) + + expectedReserveAcc, err := types.GetReserveAcc(poolCoinDenom, tc.len32) + require.NoError(t, err) + require.Equal(t, tc.expectedReserveAcc, expectedReserveAcc.String()) + } +} + +func TestGetCoinsTotalAmount(t *testing.T) { + testCases := []struct { + coins sdk.Coins + expectResult sdk.Int + }{ + { + coins: sdk.NewCoins(sdk.NewCoin("uCoinA", sdk.NewInt(100)), sdk.NewCoin("uCoinB", sdk.NewInt(100))), + expectResult: sdk.NewInt(200), + }, + { + coins: sdk.NewCoins(sdk.NewCoin("uCoinA", sdk.NewInt(100)), sdk.NewCoin("uCoinB", sdk.NewInt(300))), + expectResult: sdk.NewInt(400), + }, + { + coins: sdk.NewCoins(sdk.NewCoin("uCoinA", sdk.NewInt(500))), + expectResult: sdk.NewInt(500), + }, + } + + for _, tc := range testCases { + totalAmount := types.GetCoinsTotalAmount(tc.coins) + require.Equal(t, tc.expectResult, totalAmount) + } +} + +func TestValidateReserveCoinLimit(t *testing.T) { + testCases := []struct { + name string + maxReserveCoinAmount sdk.Int + depositCoins sdk.Coins + expectErr bool + }{ + { + name: "valid case", + maxReserveCoinAmount: sdk.ZeroInt(), // 0 means unlimited amount + depositCoins: sdk.NewCoins(sdk.NewCoin("uCoinA", sdk.NewInt(100_000_000_000)), sdk.NewCoin("uCoinB", sdk.NewInt(100))), + expectErr: false, + }, + { + name: "valid case", + maxReserveCoinAmount: sdk.NewInt(1_000_000_000_000), + depositCoins: sdk.NewCoins(sdk.NewCoin("uCoinA", sdk.NewInt(500_000_000_000)), sdk.NewCoin("uCoinB", sdk.NewInt(500_000_000_000))), + expectErr: false, + }, + { + name: "negative value of max reserve coin amount", + maxReserveCoinAmount: sdk.NewInt(-100), + depositCoins: sdk.NewCoins(sdk.NewCoin("uCoinA", sdk.NewInt(100_000_000_000)), sdk.NewCoin("uCoinB", sdk.NewInt(100))), + expectErr: true, + }, + { + name: "cannot exceed reserve coin limit amount", + maxReserveCoinAmount: sdk.NewInt(1_000_000_000_000), + depositCoins: sdk.NewCoins(sdk.NewCoin("uCoinA", sdk.NewInt(1_000_000_000_000)), sdk.NewCoin("uCoinB", sdk.NewInt(100))), + expectErr: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.expectErr { + err := types.ValidateReserveCoinLimit(tc.maxReserveCoinAmount, tc.depositCoins) + require.Equal(t, types.ErrExceededReserveCoinLimit, err) + } else { + err := types.ValidateReserveCoinLimit(tc.maxReserveCoinAmount, tc.depositCoins) + require.NoError(t, err) + } + }) + } +} + +func TestGetOfferCoinFee(t *testing.T) { + testDenom := "test" + testCases := []struct { + name string + offerCoin sdk.Coin + swapFeeRate sdk.Dec + expectOfferCoinFee sdk.Coin + }{ + { + name: "case1", + offerCoin: sdk.NewCoin(testDenom, sdk.NewInt(1)), + swapFeeRate: types.DefaultSwapFeeRate, + expectOfferCoinFee: sdk.NewCoin(testDenom, sdk.NewInt(1)), + }, + { + name: "case2", + offerCoin: sdk.NewCoin(testDenom, sdk.NewInt(10)), + swapFeeRate: types.DefaultSwapFeeRate, + expectOfferCoinFee: sdk.NewCoin(testDenom, sdk.NewInt(1)), + }, + { + name: "case3", + offerCoin: sdk.NewCoin(testDenom, sdk.NewInt(100)), + swapFeeRate: types.DefaultSwapFeeRate, + expectOfferCoinFee: sdk.NewCoin(testDenom, sdk.NewInt(1)), + }, + { + name: "case4", + offerCoin: sdk.NewCoin(testDenom, sdk.NewInt(1000)), + swapFeeRate: types.DefaultSwapFeeRate, + expectOfferCoinFee: sdk.NewCoin(testDenom, sdk.NewInt(2)), + }, + { + name: "case5", + offerCoin: sdk.NewCoin(testDenom, sdk.NewInt(10000)), + swapFeeRate: types.DefaultSwapFeeRate, + expectOfferCoinFee: sdk.NewCoin(testDenom, sdk.NewInt(15)), + }, + { + name: "case6", + offerCoin: sdk.NewCoin(testDenom, sdk.NewInt(10001)), + swapFeeRate: types.DefaultSwapFeeRate, + expectOfferCoinFee: sdk.NewCoin(testDenom, sdk.NewInt(16)), + }, + { + name: "case7", + offerCoin: sdk.NewCoin(testDenom, sdk.NewInt(10700)), + swapFeeRate: types.DefaultSwapFeeRate, + expectOfferCoinFee: sdk.NewCoin(testDenom, sdk.NewInt(17)), + }, + { + name: "case8", + offerCoin: sdk.NewCoin(testDenom, sdk.NewInt(10000)), + swapFeeRate: sdk.ZeroDec(), + expectOfferCoinFee: sdk.NewCoin(testDenom, sdk.NewInt(0)), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + require.Equal(t, tc.expectOfferCoinFee, types.GetOfferCoinFee(tc.offerCoin, tc.swapFeeRate)) + }) + } +} + +func TestCheckOverflow(t *testing.T) { + testCases := []struct { + name string + a sdk.Int + b sdk.Int + expectErr error + }{ + { + name: "valid case", + a: sdk.NewInt(10000), + b: sdk.NewInt(100), + expectErr: nil, + }, + { + name: "overflow case", + a: sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000), + b: sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000), + expectErr: types.ErrOverflowAmount, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := types.CheckOverflow(tc.a, tc.b) + require.ErrorIs(t, err, tc.expectErr) + }) + } +} + +func TestCheckOverflowWithDec(t *testing.T) { + testCases := []struct { + name string + a sdk.Dec + b sdk.Dec + expectErr error + }{ + { + name: "valid case", + a: sdk.MustNewDecFromStr("1.0"), + b: sdk.MustNewDecFromStr("0.0000001"), + expectErr: nil, + }, + { + name: "overflow case", + a: sdk.MustNewDecFromStr("100000000000000000000000000000000000000000000000000000000000.0").MulInt64(10), + b: sdk.MustNewDecFromStr("0.000000000000000001"), + expectErr: types.ErrOverflowAmount, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := types.CheckOverflowWithDec(tc.a, tc.b) + require.ErrorIs(t, err, tc.expectErr) + }) + } +} From 7bbbfbe9f70cb1b6e41d537468674108ff8c72c8 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Thu, 20 Apr 2023 16:06:15 +0700 Subject: [PATCH 02/24] add the liquidity module to the cosmos hub repo --- app/params/weights.go | 6 + app/test_helpers.go | 511 +++++++++++++++++++++ x/liquidity/client/cli/cli_test.go | 6 +- x/liquidity/client/testutil/cli_helpers.go | 10 +- x/liquidity/genesis_test.go | 2 +- x/liquidity/handler_test.go | 2 +- x/liquidity/keeper/batch_test.go | 2 +- x/liquidity/keeper/common_test.go | 8 +- x/liquidity/keeper/genesis_test.go | 2 +- x/liquidity/keeper/invariants_test.go | 2 +- x/liquidity/keeper/keeper_test.go | 2 +- x/liquidity/keeper/liquidity_pool_test.go | 2 +- x/liquidity/keeper/msg_server_test.go | 2 +- x/liquidity/keeper/querier_test.go | 2 +- x/liquidity/keeper/store_test.go | 2 +- x/liquidity/keeper/swap_test.go | 6 +- x/liquidity/simulation/operations_test.go | 6 +- x/liquidity/types/liquidity_pool_test.go | 2 +- x/liquidity/types/params_test.go | 2 +- x/liquidity/types/swap.go | 6 +- x/liquidity/types/swap_test.go | 2 +- 21 files changed, 552 insertions(+), 33 deletions(-) create mode 100644 app/test_helpers.go diff --git a/app/params/weights.go b/app/params/weights.go index 6e43b905d26..e3654efd040 100644 --- a/app/params/weights.go +++ b/app/params/weights.go @@ -21,4 +21,10 @@ const ( DefaultWeightCommunitySpendProposal int = 5 DefaultWeightTextProposal int = 5 DefaultWeightParamChangeProposal int = 5 + + // liquidity module simulation operation weights for messages + DefaultWeightMsgCreatePool int = 5 + DefaultWeightMsgDepositWithinBatch int = 10 + DefaultWeightMsgWithdrawWithinBatch int = 10 + DefaultWeightMsgSwapWithinBatch int = 85 ) diff --git a/app/test_helpers.go b/app/test_helpers.go new file mode 100644 index 00000000000..7e9d3da2f8c --- /dev/null +++ b/app/test_helpers.go @@ -0,0 +1,511 @@ +package gaia + +// DONTCOVER + +import ( + "bytes" + "encoding/json" + "fmt" + "math" + "math/rand" + "strconv" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + appparams "github.com/cosmos/gaia/v9/app/params" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtypes "github.com/tendermint/tendermint/types" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/gaia/v9/x/liquidity" + "github.com/cosmos/gaia/v9/x/liquidity/keeper" + "github.com/cosmos/gaia/v9/x/liquidity/types" +) + +// DefaultConsensusParams defines the default Tendermint consensus params used in +// GaiaApp testing. +var DefaultConsensusParams = &abci.ConsensusParams{ + Block: &abci.BlockParams{ + MaxBytes: 200000, + MaxGas: 2000000, + }, + Evidence: &tmproto.EvidenceParams{ + MaxAgeNumBlocks: 302400, + MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration + }, + Validator: &tmproto.ValidatorParams{ + PubKeyTypes: []string{ + tmtypes.ABCIPubKeyTypeEd25519, + }, + }, +} + +func setup(withGenesis bool, invCheckPeriod uint) (*GaiaApp, GenesisState) { + db := dbm.NewMemDB() + encCdc := appparams.MakeTestEncodingConfig() + app := NewGaiaApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, invCheckPeriod, encCdc, EmptyAppOptions{}) + if withGenesis { + return app, NewDefaultGenesisState() + } + return app, GenesisState{} +} + +// Setup initializes a new GaiaApp. A Nop logger is set in GaiaApp. +func Setup(isCheckTx bool) *GaiaApp { + app, genesisState := setup(!isCheckTx, 5) + if !isCheckTx { + // init chain must be called to stop deliverState from being nil + stateBytes, err := json.MarshalIndent(genesisState, "", " ") + if err != nil { + panic(err) + } + + // Initialize the chain + app.InitChain( + abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: DefaultConsensusParams, + AppStateBytes: stateBytes, + }, + ) + } + + return app +} + +type GenerateAccountStrategy func(int) []sdk.AccAddress + +// createIncrementalAccounts is a strategy used by addTestAddrs() in order to generated addresses in ascending order. +func createIncrementalAccounts(accNum int) []sdk.AccAddress { + var addresses []sdk.AccAddress + var buffer bytes.Buffer + + // start at 100 so we can make up to 999 test addresses with valid test addresses + for i := 100; i < (accNum + 100); i++ { + numString := strconv.Itoa(i) + buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") // base address string + + buffer.WriteString(numString) // adding on final two digits to make addresses unique + res, _ := sdk.AccAddressFromHex(buffer.String()) + bech := res.String() + addr, _ := TestAddr(buffer.String(), bech) + + addresses = append(addresses, addr) + buffer.Reset() + } + + return addresses +} + +// AddRandomTestAddr creates new account with random address. +func AddRandomTestAddr(app *GaiaApp, ctx sdk.Context, initCoins sdk.Coins) sdk.AccAddress { + addr := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) + SaveAccount(app, ctx, addr, initCoins) + return addr +} + +// AddTestAddrs constructs and returns accNum amount of accounts with an +// initial balance of accAmt in random order +func AddTestAddrs(app *GaiaApp, ctx sdk.Context, accNum int, initCoins sdk.Coins) []sdk.AccAddress { + testAddrs := createIncrementalAccounts(accNum) + for _, addr := range testAddrs { + if err := FundAccount(app, ctx, addr, initCoins); err != nil { + panic(err) + } + } + return testAddrs +} + +// permission of minting, create a "faucet" account. (@fdymylja) +func FundAccount(app *GaiaApp, ctx sdk.Context, addr sdk.AccAddress, amounts sdk.Coins) error { + if err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { + return err + } + return app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, amounts) +} + +// AddTestAddrs constructs and returns accNum amount of accounts with an +// initial balance of accAmt in random order +func AddTestAddrsIncremental(app *GaiaApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { + return addTestAddrs(app, ctx, accNum, accAmt, createIncrementalAccounts) +} + +func addTestAddrs(app *GaiaApp, ctx sdk.Context, accNum int, accAmt sdk.Int, strategy GenerateAccountStrategy) []sdk.AccAddress { + testAddrs := strategy(accNum) + + initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) + + for _, addr := range testAddrs { + if err := FundAccount(app, ctx, addr, initCoins); err != nil { + panic(err) + } + } + + return testAddrs +} + +// SaveAccount saves the provided account into the simapp with balance based on initCoins. +func SaveAccount(app *GaiaApp, ctx sdk.Context, addr sdk.AccAddress, initCoins sdk.Coins) { + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + app.AccountKeeper.SetAccount(ctx, acc) + if initCoins.IsAllPositive() { + err := FundAccount(app, ctx, addr, initCoins) + if err != nil { + panic(err) + } + } +} + +func SaveAccountWithFee(app *GaiaApp, ctx sdk.Context, addr sdk.AccAddress, initCoins sdk.Coins, offerCoin sdk.Coin) { + SaveAccount(app, ctx, addr, initCoins) + params := app.LiquidityKeeper.GetParams(ctx) + offerCoinFee := types.GetOfferCoinFee(offerCoin, params.SwapFeeRate) + err := FundAccount(app, ctx, addr, sdk.NewCoins(offerCoinFee)) + if err != nil { + panic(err) + } +} + +func TestAddr(addr string, bech string) (sdk.AccAddress, error) { + res, err := sdk.AccAddressFromHex(addr) + if err != nil { + return nil, err + } + bechexpected := res.String() + if bech != bechexpected { + return nil, fmt.Errorf("bech encoding doesn't match reference") + } + + bechres, err := sdk.AccAddressFromBech32(bech) + if err != nil { + return nil, err + } + if !bytes.Equal(bechres, res) { + return nil, err + } + + return res, nil +} + +// CreateTestInput returns a simapp with custom LiquidityKeeper to avoid +// messing with the hooks. +func CreateTestInput() (*GaiaApp, sdk.Context) { + cdc := codec.NewLegacyAmino() + types.RegisterLegacyAminoCodec(cdc) + keeper.BatchLogicInvariantCheckFlag = true + + app := Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + + appCodec := app.AppCodec() + + app.LiquidityKeeper = keeper.NewKeeper( + appCodec, + app.GetKey(types.StoreKey), + app.GetSubspace(types.ModuleName), + app.BankKeeper, + app.AccountKeeper, + app.DistrKeeper, + ) + + return app, ctx +} + +func GetRandPoolAmt(r *rand.Rand, minInitDepositAmt sdk.Int) (x, y sdk.Int) { + x = GetRandRange(r, int(minInitDepositAmt.Int64()), 100000000000000).MulRaw(int64(math.Pow10(r.Intn(10)))) + y = GetRandRange(r, int(minInitDepositAmt.Int64()), 100000000000000).MulRaw(int64(math.Pow10(r.Intn(10)))) + return +} + +func GetRandRange(r *rand.Rand, min, max int) sdk.Int { + return sdk.NewInt(int64(r.Intn(max-min) + min)) +} + +func GetRandomSizeOrders(denomX, denomY string, x, y sdk.Int, r *rand.Rand, sizeXToY, sizeYToX int32) (xToY, yToX []*types.MsgSwapWithinBatch) { + randomSizeXtoY := int(r.Int31n(sizeXToY)) + randomSizeYtoX := int(r.Int31n(sizeYToX)) + return GetRandomOrders(denomX, denomY, x, y, r, randomSizeXtoY, randomSizeYtoX) +} + +func GetRandomOrders(denomX, denomY string, x, y sdk.Int, r *rand.Rand, sizeXToY, sizeYToX int) (xToY, yToX []*types.MsgSwapWithinBatch) { + currentPrice := x.ToDec().Quo(y.ToDec()) + + for len(xToY) < sizeXToY { + orderPrice := currentPrice.Mul(sdk.NewDecFromIntWithPrec(GetRandRange(r, 991, 1009), 3)) + orderAmt := sdk.ZeroDec() //nolint:staticcheck + if r.Intn(2) == 1 { + orderAmt = x.ToDec().Mul(sdk.NewDecFromIntWithPrec(GetRandRange(r, 1, 100), 4)) + } else { + orderAmt = sdk.NewDecFromIntWithPrec(GetRandRange(r, 1000, 10000), 0) + } + if orderAmt.Quo(orderPrice).TruncateInt().IsZero() { + continue + } + orderCoin := sdk.NewCoin(denomX, orderAmt.Ceil().TruncateInt()) + + xToY = append(xToY, &types.MsgSwapWithinBatch{ + OfferCoin: orderCoin, + DemandCoinDenom: denomY, + OrderPrice: orderPrice, + }) + } + + for len(yToX) < sizeYToX { + orderPrice := currentPrice.Mul(sdk.NewDecFromIntWithPrec(GetRandRange(r, 991, 1009), 3)) + orderAmt := sdk.ZeroDec() //nolint:staticcheck + if r.Intn(2) == 1 { + orderAmt = y.ToDec().Mul(sdk.NewDecFromIntWithPrec(GetRandRange(r, 1, 100), 4)) + } else { + orderAmt = sdk.NewDecFromIntWithPrec(GetRandRange(r, 1000, 10000), 0) + } + if orderAmt.Mul(orderPrice).TruncateInt().IsZero() { + continue + } + orderCoin := sdk.NewCoin(denomY, orderAmt.Ceil().TruncateInt()) + + yToX = append(yToX, &types.MsgSwapWithinBatch{ + OfferCoin: orderCoin, + DemandCoinDenom: denomX, + OrderPrice: orderPrice, + }) + } + return xToY, yToX +} + +func TestCreatePool(t *testing.T, simapp *GaiaApp, ctx sdk.Context, x, y sdk.Int, denomX, denomY string, addr sdk.AccAddress) uint64 { + deposit := sdk.NewCoins(sdk.NewCoin(denomX, x), sdk.NewCoin(denomY, y)) + params := simapp.LiquidityKeeper.GetParams(ctx) + // set accounts for creator, depositor, withdrawer, balance for deposit + SaveAccount(simapp, ctx, addr, deposit.Add(params.PoolCreationFee...)) // pool creator + depositX := simapp.BankKeeper.GetBalance(ctx, addr, denomX) + depositY := simapp.BankKeeper.GetBalance(ctx, addr, denomY) + depositBalance := sdk.NewCoins(depositX, depositY) + require.Equal(t, deposit, depositBalance) + + // create Liquidity pool + poolTypeID := types.DefaultPoolTypeID + poolID := simapp.LiquidityKeeper.GetNextPoolID(ctx) + msg := types.NewMsgCreatePool(addr, poolTypeID, depositBalance) + _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) + require.NoError(t, err) + + // verify created liquidity pool + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + require.Equal(t, poolID, pool.Id) + require.Equal(t, denomX, pool.ReserveCoinDenoms[0]) + require.Equal(t, denomY, pool.ReserveCoinDenoms[1]) + + // verify minted pool coin + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + creatorBalance := simapp.BankKeeper.GetBalance(ctx, addr, pool.PoolCoinDenom) + require.Equal(t, poolCoin, creatorBalance.Amount) + return poolID +} + +func TestDepositPool(t *testing.T, simapp *GaiaApp, ctx sdk.Context, x, y sdk.Int, addrs []sdk.AccAddress, poolID uint64, withEndblock bool) { + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + denomX, denomY := pool.ReserveCoinDenoms[0], pool.ReserveCoinDenoms[1] + deposit := sdk.NewCoins(sdk.NewCoin(denomX, x), sdk.NewCoin(denomY, y)) + + moduleAccAddress := simapp.AccountKeeper.GetModuleAddress(types.ModuleName) + moduleAccEscrowAmtX := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, denomX) + moduleAccEscrowAmtY := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, denomY) + iterNum := len(addrs) + for i := 0; i < iterNum; i++ { + SaveAccount(simapp, ctx, addrs[i], deposit) // pool creator + + depositMsg := types.NewMsgDepositWithinBatch(addrs[i], poolID, deposit) + _, err := simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + + depositorBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.ReserveCoinDenoms[0]) + depositorBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.ReserveCoinDenoms[1]) + require.Equal(t, denomX, depositorBalanceX.Denom) + require.Equal(t, denomY, depositorBalanceY.Denom) + + // check escrow balance of module account + moduleAccEscrowAmtX = moduleAccEscrowAmtX.Add(deposit[0]) + moduleAccEscrowAmtY = moduleAccEscrowAmtY.Add(deposit[1]) + moduleAccEscrowAmtXAfter := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, denomX) + moduleAccEscrowAmtYAfter := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, denomY) + require.Equal(t, moduleAccEscrowAmtX, moduleAccEscrowAmtXAfter) + require.Equal(t, moduleAccEscrowAmtY, moduleAccEscrowAmtYAfter) + } + batch, bool := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, bool) + + // endblock + if withEndblock { + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, batch) + for i := 0; i < iterNum; i++ { + // verify minted pool coin + poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + depositorPoolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.PoolCoinDenom) + require.NotEqual(t, sdk.ZeroInt(), depositorPoolCoinBalance) + require.NotEqual(t, sdk.ZeroInt(), poolCoin) + + require.True(t, msgs[i].Executed) + require.True(t, msgs[i].Succeeded) + require.True(t, msgs[i].ToBeDeleted) + + // error balance after endblock + depositorBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.ReserveCoinDenoms[0]) + depositorBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.ReserveCoinDenoms[1]) + require.Equal(t, denomX, depositorBalanceX.Denom) + require.Equal(t, denomY, depositorBalanceY.Denom) + } + } +} + +func TestWithdrawPool(t *testing.T, simapp *GaiaApp, ctx sdk.Context, poolCoinAmt sdk.Int, addrs []sdk.AccAddress, poolID uint64, withEndblock bool) { + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + moduleAccAddress := simapp.AccountKeeper.GetModuleAddress(types.ModuleName) + moduleAccEscrowAmtPool := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, pool.PoolCoinDenom) + + iterNum := len(addrs) + for i := 0; i < iterNum; i++ { + balancePoolCoin := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.PoolCoinDenom) + require.True(t, balancePoolCoin.Amount.GTE(poolCoinAmt)) + + withdrawCoin := sdk.NewCoin(pool.PoolCoinDenom, poolCoinAmt) + withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[i], poolID, withdrawCoin) + _, err := simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + require.NoError(t, err) + + moduleAccEscrowAmtPoolAfter := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, pool.PoolCoinDenom) + moduleAccEscrowAmtPool.Amount = moduleAccEscrowAmtPool.Amount.Add(withdrawMsg.PoolCoin.Amount) + require.Equal(t, moduleAccEscrowAmtPool, moduleAccEscrowAmtPoolAfter) + + balancePoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.PoolCoinDenom) + if balancePoolCoin.Amount.Equal(withdrawCoin.Amount) { + } else { + require.Equal(t, balancePoolCoin.Sub(withdrawCoin).Amount, balancePoolCoinAfter.Amount) + } + + } + + if withEndblock { + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + + // endblock + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + batch, bool := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, bool) + + // verify burned pool coin + poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + fmt.Println(poolCoinAfter, poolCoinBefore) + require.True(t, poolCoinAfter.LT(poolCoinBefore)) + + for i := 0; i < iterNum; i++ { + withdrawerBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.ReserveCoinDenoms[0]) + withdrawerBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.ReserveCoinDenoms[1]) + require.True(t, withdrawerBalanceX.IsPositive()) + require.True(t, withdrawerBalanceY.IsPositive()) + + withdrawMsgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, batch) + require.True(t, withdrawMsgs[i].Executed) + require.True(t, withdrawMsgs[i].Succeeded) + require.True(t, withdrawMsgs[i].ToBeDeleted) + } + } +} + +func TestSwapPool(t *testing.T, simapp *GaiaApp, ctx sdk.Context, offerCoins []sdk.Coin, orderPrices []sdk.Dec, + addrs []sdk.AccAddress, poolID uint64, withEndblock bool, +) ([]*types.SwapMsgState, types.PoolBatch) { + if len(offerCoins) != len(orderPrices) || len(orderPrices) != len(addrs) { + require.True(t, false) + } + + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + moduleAccAddress := simapp.AccountKeeper.GetModuleAddress(types.ModuleName) + + var swapMsgStates []*types.SwapMsgState + + params := simapp.LiquidityKeeper.GetParams(ctx) + + iterNum := len(addrs) + for i := 0; i < iterNum; i++ { + moduleAccEscrowAmtPool := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, offerCoins[i].Denom) + currentBalance := simapp.BankKeeper.GetBalance(ctx, addrs[i], offerCoins[i].Denom) + if currentBalance.IsLT(offerCoins[i]) { + SaveAccountWithFee(simapp, ctx, addrs[i], sdk.NewCoins(offerCoins[i]), offerCoins[i]) + } + var demandCoinDenom string + if pool.ReserveCoinDenoms[0] == offerCoins[i].Denom { + demandCoinDenom = pool.ReserveCoinDenoms[1] + } else if pool.ReserveCoinDenoms[1] == offerCoins[i].Denom { + demandCoinDenom = pool.ReserveCoinDenoms[0] + } else { + require.True(t, false) + } + + swapMsg := types.NewMsgSwapWithinBatch(addrs[i], poolID, types.DefaultSwapTypeID, offerCoins[i], demandCoinDenom, orderPrices[i], params.SwapFeeRate) + batchPoolSwapMsg, err := simapp.LiquidityKeeper.SwapWithinBatch(ctx, swapMsg, 0) + require.NoError(t, err) + + swapMsgStates = append(swapMsgStates, batchPoolSwapMsg) + moduleAccEscrowAmtPoolAfter := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, offerCoins[i].Denom) + moduleAccEscrowAmtPool.Amount = moduleAccEscrowAmtPool.Amount.Add(offerCoins[i].Amount).Add(types.GetOfferCoinFee(offerCoins[i], params.SwapFeeRate).Amount) + require.Equal(t, moduleAccEscrowAmtPool, moduleAccEscrowAmtPoolAfter) + + } + batch, _ := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + + if withEndblock { + // endblock + liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) + + batch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) + } + return swapMsgStates, batch +} + +func GetSwapMsg(t *testing.T, simapp *GaiaApp, ctx sdk.Context, offerCoins []sdk.Coin, orderPrices []sdk.Dec, + addrs []sdk.AccAddress, poolID uint64, +) []*types.MsgSwapWithinBatch { + if len(offerCoins) != len(orderPrices) || len(orderPrices) != len(addrs) { + require.True(t, false) + } + + var msgs []*types.MsgSwapWithinBatch + pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) + require.True(t, found) + + params := simapp.LiquidityKeeper.GetParams(ctx) + + iterNum := len(addrs) + for i := 0; i < iterNum; i++ { + currentBalance := simapp.BankKeeper.GetBalance(ctx, addrs[i], offerCoins[i].Denom) + if currentBalance.IsLT(offerCoins[i]) { + SaveAccountWithFee(simapp, ctx, addrs[i], sdk.NewCoins(offerCoins[i]), offerCoins[i]) + } + var demandCoinDenom string + if pool.ReserveCoinDenoms[0] == offerCoins[i].Denom { + demandCoinDenom = pool.ReserveCoinDenoms[1] + } else if pool.ReserveCoinDenoms[1] == offerCoins[i].Denom { + demandCoinDenom = pool.ReserveCoinDenoms[0] + } else { + require.True(t, false) + } + + msgs = append(msgs, types.NewMsgSwapWithinBatch(addrs[i], poolID, types.DefaultSwapTypeID, offerCoins[i], demandCoinDenom, orderPrices[i], params.SwapFeeRate)) + } + return msgs +} diff --git a/x/liquidity/client/cli/cli_test.go b/x/liquidity/client/cli/cli_test.go index 2bf56bec506..0c2dc70628a 100644 --- a/x/liquidity/client/cli/cli_test.go +++ b/x/liquidity/client/cli/cli_test.go @@ -1568,15 +1568,15 @@ func (s *IntegrationTestSuite) TestExportGenesis() { logger := serverCtx.Logger db := s.db - var app *lapp.LiquidityApp + var app *lapp.GaiaApp if height != -1 { - app = lapp.NewLiquidityApp(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), encCfg, appOpts) + app = lapp.NewGaiaApp(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), encCfg, appOpts) if err := app.LoadHeight(height); err != nil { return servertypes.ExportedApp{}, err } } else { - app = lapp.NewLiquidityApp(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), encCfg, appOpts) + app = lapp.NewGaiaApp(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), encCfg, appOpts) } return app.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) diff --git a/x/liquidity/client/testutil/cli_helpers.go b/x/liquidity/client/testutil/cli_helpers.go index c89cf14f997..6c40bd2584e 100644 --- a/x/liquidity/client/testutil/cli_helpers.go +++ b/x/liquidity/client/testutil/cli_helpers.go @@ -17,7 +17,7 @@ import ( govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli" paramscli "github.com/cosmos/cosmos-sdk/x/params/client/cli" - liquidityapp "github.com/cosmos/gaia/v9/app" + GaiaApp "github.com/cosmos/gaia/v9/app" liquiditycli "github.com/cosmos/gaia/v9/x/liquidity/client/cli" dbm "github.com/tendermint/tm-db" @@ -29,17 +29,17 @@ func NewConfig(dbm *dbm.MemDB) network.Config { encCfg := simapp.MakeTestEncodingConfig() cfg := network.DefaultConfig() - cfg.AppConstructor = NewAppConstructor(encCfg, dbm) // the ABCI application constructor - cfg.GenesisState = liquidityapp.ModuleBasics.DefaultGenesis(cfg.Codec) // liquidity genesis state to provide + cfg.AppConstructor = NewAppConstructor(encCfg, dbm) // the ABCI application constructor + cfg.GenesisState = GaiaApp.ModuleBasics.DefaultGenesis(cfg.Codec) // liquidity genesis state to provide return cfg } // NewAppConstructor returns a new network AppConstructor. func NewAppConstructor(encodingCfg params.EncodingConfig, db *dbm.MemDB) network.AppConstructor { return func(val network.Validator) servertypes.Application { - return liquidityapp.NewLiquidityApp( + return GaiaApp.NewGaiaApp( val.Ctx.Logger, db, nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0, - liquidityapp.MakeEncodingConfig(), + GaiaApp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}, baseapp.SetPruning(storetypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices), diff --git a/x/liquidity/genesis_test.go b/x/liquidity/genesis_test.go index 2eaa483d75b..0bb50b7a358 100644 --- a/x/liquidity/genesis_test.go +++ b/x/liquidity/genesis_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/types" ) diff --git a/x/liquidity/handler_test.go b/x/liquidity/handler_test.go index a63f69f0fb8..eade4777cff 100644 --- a/x/liquidity/handler_test.go +++ b/x/liquidity/handler_test.go @@ -9,7 +9,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/types" ) diff --git a/x/liquidity/keeper/batch_test.go b/x/liquidity/keeper/batch_test.go index a91f0dd4e4f..5ec51d34bd0 100644 --- a/x/liquidity/keeper/batch_test.go +++ b/x/liquidity/keeper/batch_test.go @@ -8,7 +8,7 @@ import ( distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/types" ) diff --git a/x/liquidity/keeper/common_test.go b/x/liquidity/keeper/common_test.go index 0408e49116e..e796207cd5c 100644 --- a/x/liquidity/keeper/common_test.go +++ b/x/liquidity/keeper/common_test.go @@ -5,18 +5,18 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/types" ) // createTestInput Returns a simapp with custom LiquidityKeeper // to avoid messing with the hooks. -func createTestInput() (*app.LiquidityApp, sdk.Context) { +func createTestInput() (*app.GaiaApp, sdk.Context) { return app.CreateTestInput() } -func createLiquidity(t *testing.T, ctx sdk.Context, simapp *app.LiquidityApp) ( +func createLiquidity(t *testing.T, ctx sdk.Context, simapp *app.GaiaApp) ( []sdk.AccAddress, []types.Pool, []types.PoolBatch, []types.DepositMsgState, []types.WithdrawMsgState, ) { @@ -78,7 +78,7 @@ func createLiquidity(t *testing.T, ctx sdk.Context, simapp *app.LiquidityApp) ( return addrs, pools, batches, depositMsgs, withdrawMsgs } -func createTestPool(X, Y sdk.Coin) (*app.LiquidityApp, sdk.Context, types.Pool, sdk.AccAddress, error) { +func createTestPool(X, Y sdk.Coin) (*app.GaiaApp, sdk.Context, types.Pool, sdk.AccAddress, error) { simapp, ctx := createTestInput() params := simapp.LiquidityKeeper.GetParams(ctx) diff --git a/x/liquidity/keeper/genesis_test.go b/x/liquidity/keeper/genesis_test.go index 2a2f52f8076..7587bac020e 100644 --- a/x/liquidity/keeper/genesis_test.go +++ b/x/liquidity/keeper/genesis_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/types" ) diff --git a/x/liquidity/keeper/invariants_test.go b/x/liquidity/keeper/invariants_test.go index 944e2d0ddd0..49625ee302a 100644 --- a/x/liquidity/keeper/invariants_test.go +++ b/x/liquidity/keeper/invariants_test.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/keeper" "github.com/cosmos/gaia/v9/x/liquidity/types" diff --git a/x/liquidity/keeper/keeper_test.go b/x/liquidity/keeper/keeper_test.go index 578a96b3f5d..19ba696af36 100644 --- a/x/liquidity/keeper/keeper_test.go +++ b/x/liquidity/keeper/keeper_test.go @@ -16,7 +16,7 @@ import ( type KeeperTestSuite struct { suite.Suite - app *lapp.LiquidityApp + app *lapp.GaiaApp ctx sdk.Context addrs []sdk.AccAddress pools []types.Pool diff --git a/x/liquidity/keeper/liquidity_pool_test.go b/x/liquidity/keeper/liquidity_pool_test.go index ee51b56396c..fb90c79a3a8 100644 --- a/x/liquidity/keeper/liquidity_pool_test.go +++ b/x/liquidity/keeper/liquidity_pool_test.go @@ -9,7 +9,7 @@ import ( distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/keeper" "github.com/cosmos/gaia/v9/x/liquidity/types" diff --git a/x/liquidity/keeper/msg_server_test.go b/x/liquidity/keeper/msg_server_test.go index f841678c081..981449b6f8c 100644 --- a/x/liquidity/keeper/msg_server_test.go +++ b/x/liquidity/keeper/msg_server_test.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/types" ) diff --git a/x/liquidity/keeper/querier_test.go b/x/liquidity/keeper/querier_test.go index ac4c5b2e005..977da745be8 100644 --- a/x/liquidity/keeper/querier_test.go +++ b/x/liquidity/keeper/querier_test.go @@ -11,7 +11,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity/keeper" "github.com/cosmos/gaia/v9/x/liquidity/types" ) diff --git a/x/liquidity/keeper/store_test.go b/x/liquidity/keeper/store_test.go index 5c2cab71eb9..fa9f118167b 100644 --- a/x/liquidity/keeper/store_test.go +++ b/x/liquidity/keeper/store_test.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/types" ) diff --git a/x/liquidity/keeper/swap_test.go b/x/liquidity/keeper/swap_test.go index 654da75a377..836535d71da 100644 --- a/x/liquidity/keeper/swap_test.go +++ b/x/liquidity/keeper/swap_test.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/types" ) @@ -138,7 +138,7 @@ func TestSwapExecution(t *testing.T) { } } -func testSwapEdgeCases(t *testing.T, r *rand.Rand, simapp *app.LiquidityApp, ctx sdk.Context, X, Y sdk.Int, depositBalance sdk.Coins, addrs []sdk.AccAddress) { +func testSwapEdgeCases(t *testing.T, r *rand.Rand, simapp *app.GaiaApp, ctx sdk.Context, X, Y sdk.Int, depositBalance sdk.Coins, addrs []sdk.AccAddress) { // simapp, ctx := createTestInput() simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) params := simapp.LiquidityKeeper.GetParams(ctx) @@ -347,7 +347,7 @@ func TestSwapWithDepletedPool(t *testing.T) { liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) } -func createPool(simapp *app.LiquidityApp, ctx sdk.Context, X, Y sdk.Int, denomX, denomY string) (types.Pool, error) { +func createPool(simapp *app.GaiaApp, ctx sdk.Context, X, Y sdk.Int, denomX, denomY string) (types.Pool, error) { params := simapp.LiquidityKeeper.GetParams(ctx) coins := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) diff --git a/x/liquidity/simulation/operations_test.go b/x/liquidity/simulation/operations_test.go index 69163b111fd..5443874a11e 100644 --- a/x/liquidity/simulation/operations_test.go +++ b/x/liquidity/simulation/operations_test.go @@ -184,7 +184,7 @@ func TestSimulateMsgSwapWithinBatch(t *testing.T) { require.Len(t, futureOperations, 0) } -func createTestApp(isCheckTx bool) (*lapp.LiquidityApp, sdk.Context) { +func createTestApp(isCheckTx bool) (*lapp.GaiaApp, sdk.Context) { app := lapp.Setup(false) ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{}) @@ -194,7 +194,7 @@ func createTestApp(isCheckTx bool) (*lapp.LiquidityApp, sdk.Context) { return app, ctx } -func getTestingAccounts(t *testing.T, r *rand.Rand, app *lapp.LiquidityApp, ctx sdk.Context, n int) []simtypes.Account { +func getTestingAccounts(t *testing.T, r *rand.Rand, app *lapp.GaiaApp, ctx sdk.Context, n int) []simtypes.Account { accounts := simtypes.RandomAccounts(r, n) initAmt := sdk.TokensFromConsensusPower(1_000_000, sdk.DefaultPowerReduction) @@ -210,7 +210,7 @@ func getTestingAccounts(t *testing.T, r *rand.Rand, app *lapp.LiquidityApp, ctx return accounts } -func setupLiquidityPools(t *testing.T, r *rand.Rand, app *lapp.LiquidityApp, ctx sdk.Context, accounts []simtypes.Account) { +func setupLiquidityPools(t *testing.T, r *rand.Rand, app *lapp.GaiaApp, ctx sdk.Context, accounts []simtypes.Account) { params := app.StakingKeeper.GetParams(ctx) for _, account := range accounts { diff --git a/x/liquidity/types/liquidity_pool_test.go b/x/liquidity/types/liquidity_pool_test.go index 1f23a569fd6..71d8d06d5bd 100644 --- a/x/liquidity/types/liquidity_pool_test.go +++ b/x/liquidity/types/liquidity_pool_test.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity/types" ) diff --git a/x/liquidity/types/params_test.go b/x/liquidity/types/params_test.go index 747d3ee5701..907b8fb266a 100644 --- a/x/liquidity/types/params_test.go +++ b/x/liquidity/types/params_test.go @@ -8,7 +8,7 @@ import ( paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity/types" ) diff --git a/x/liquidity/types/swap.go b/x/liquidity/types/swap.go index ccd46320b18..a267c1e56c4 100644 --- a/x/liquidity/types/swap.go +++ b/x/liquidity/types/swap.go @@ -454,7 +454,8 @@ func CheckSwapPrice(matchResultXtoY, matchResultYtoX []MatchResult, swapPrice sd // Find matched orders and set status for msgs func FindOrderMatch(direction OrderDirection, swapMsgStates []*SwapMsgState, executableAmt, swapPrice sdk.Dec, height int64) ( - matchResults []MatchResult, poolXDelta, poolYDelta sdk.Dec) { + matchResults []MatchResult, poolXDelta, poolYDelta sdk.Dec, +) { poolXDelta = sdk.ZeroDec() poolYDelta = sdk.ZeroDec() @@ -550,7 +551,8 @@ func FindOrderMatch(direction OrderDirection, swapMsgStates []*SwapMsgState, exe // UpdateSwapMsgStates updates SwapMsgStates using the MatchResults. func UpdateSwapMsgStates(x, y sdk.Dec, xToY, yToX []*SwapMsgState, matchResultXtoY, matchResultYtoX []MatchResult) ( - []*SwapMsgState, []*SwapMsgState, sdk.Dec, sdk.Dec, sdk.Dec, sdk.Dec) { + []*SwapMsgState, []*SwapMsgState, sdk.Dec, sdk.Dec, sdk.Dec, sdk.Dec, +) { sort.SliceStable(xToY, func(i, j int) bool { return xToY[i].Msg.OrderPrice.GT(xToY[j].Msg.OrderPrice) }) diff --git a/x/liquidity/types/swap_test.go b/x/liquidity/types/swap_test.go index 47ee3154f4c..95bcb5774dd 100644 --- a/x/liquidity/types/swap_test.go +++ b/x/liquidity/types/swap_test.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/cosmos/gaia/v9/app" + app "github.com/cosmos/gaia/v9/app" "github.com/cosmos/gaia/v9/x/liquidity" "github.com/cosmos/gaia/v9/x/liquidity/types" ) From 467055c501aee7e517afa253880eb158cecf6274 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Thu, 20 Apr 2023 16:21:44 +0700 Subject: [PATCH 03/24] lint unused parameters --- app/app.go | 6 +++--- app/app_test.go | 2 +- app/helpers/test_helpers.go | 2 +- app/upgrades/v7/upgrades.go | 2 +- app/upgrades/v9/upgrades.go | 2 +- tests/e2e/e2e_globalfee_proposal_test.go | 2 +- x/globalfee/module.go | 16 ++++++++-------- x/liquidity/client/testutil/cli_helpers.go | 10 +++++----- x/liquidity/keeper/grpc_query.go | 2 +- x/liquidity/keeper/invariants.go | 2 +- x/liquidity/module.go | 6 +++--- x/liquidity/simulation/genesis.go | 2 +- x/liquidity/simulation/operations_test.go | 2 +- x/liquidity/simulation/params.go | 2 +- x/liquidity/types/swap.go | 2 +- 15 files changed, 30 insertions(+), 30 deletions(-) diff --git a/app/app.go b/app/app.go index f08859b12ff..6a8650bebae 100644 --- a/app/app.go +++ b/app/app.go @@ -414,10 +414,10 @@ func RegisterSwaggerAPI(rtr *mux.Router) { rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer)) } -func (app *GaiaApp) OnTxSucceeded(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { +func (app *GaiaApp) OnTxSucceeded(_ sdk.Context, _, _ string, _ []byte, _ []byte) { } -func (app *GaiaApp) OnTxFailed(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { +func (app *GaiaApp) OnTxFailed(_ sdk.Context, _, _ string, _ []byte, _ []byte) { } // TestingApp functions @@ -436,6 +436,6 @@ func (app *GaiaApp) GetTxConfig() client.TxConfig { type EmptyAppOptions struct{} // Get implements AppOptions -func (ao EmptyAppOptions) Get(o string) interface{} { +func (ao EmptyAppOptions) Get(_ string) interface{} { return nil } diff --git a/app/app_test.go b/app/app_test.go index f5b29d8f526..3f3e6b6ae33 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -14,7 +14,7 @@ import ( type EmptyAppOptions struct{} -func (ao EmptyAppOptions) Get(o string) interface{} { +func (ao EmptyAppOptions) Get(_ string) interface{} { return nil } diff --git a/app/helpers/test_helpers.go b/app/helpers/test_helpers.go index a0a61634ae2..d6361bcb0bc 100644 --- a/app/helpers/test_helpers.go +++ b/app/helpers/test_helpers.go @@ -64,7 +64,7 @@ func (pv PV) GetPubKey() (crypto.PubKey, error) { type EmptyAppOptions struct{} -func (EmptyAppOptions) Get(o string) interface{} { return nil } +func (EmptyAppOptions) Get(_ string) interface{} { return nil } func Setup(t *testing.T) *gaiaapp.GaiaApp { t.Helper() diff --git a/app/upgrades/v7/upgrades.go b/app/upgrades/v7/upgrades.go index c68799b56ea..3ba7db9affd 100644 --- a/app/upgrades/v7/upgrades.go +++ b/app/upgrades/v7/upgrades.go @@ -15,7 +15,7 @@ import ( func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, - keepers *keepers.AppKeepers, + _ *keepers.AppKeepers, ) upgradetypes.UpgradeHandler { return func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { vm[icatypes.ModuleName] = mm.Modules[icatypes.ModuleName].ConsensusVersion() diff --git a/app/upgrades/v9/upgrades.go b/app/upgrades/v9/upgrades.go index 3ae7b17bec1..44a20a120ac 100644 --- a/app/upgrades/v9/upgrades.go +++ b/app/upgrades/v9/upgrades.go @@ -10,7 +10,7 @@ import ( func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, - keepers *keepers.AppKeepers, + _ *keepers.AppKeepers, ) upgradetypes.UpgradeHandler { return func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { ctx.Logger().Info("Starting module migrations...") diff --git a/tests/e2e/e2e_globalfee_proposal_test.go b/tests/e2e/e2e_globalfee_proposal_test.go index 3f48007af6d..8c4063171e9 100644 --- a/tests/e2e/e2e_globalfee_proposal_test.go +++ b/tests/e2e/e2e_globalfee_proposal_test.go @@ -10,7 +10,7 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) -func (s *IntegrationTestSuite) govProposeNewGlobalfee(newGlobalfee sdk.DecCoins, proposalCounter int, submitter string, fees string) { //nolint:unparam +func (s *IntegrationTestSuite) govProposeNewGlobalfee(newGlobalfee sdk.DecCoins, proposalCounter int, submitter string, _ string) { //nolint:unparam s.writeGovParamChangeProposalGlobalFees(s.chainA, newGlobalfee) chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) submitGovFlags := []string{"param-change", configFile(proposalGlobalFeeFilename)} diff --git a/x/globalfee/module.go b/x/globalfee/module.go index 2549e8403ce..d2cf91c0f41 100644 --- a/x/globalfee/module.go +++ b/x/globalfee/module.go @@ -39,7 +39,7 @@ func (a AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { }) } -func (a AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, config client.TxEncodingConfig, message json.RawMessage) error { +func (a AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, _ client.TxEncodingConfig, message json.RawMessage) error { var data types.GenesisState err := marshaler.UnmarshalJSON(message, &data) if err != nil { @@ -51,10 +51,10 @@ func (a AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, config client return nil } -func (a AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { +func (a AppModuleBasic) RegisterInterfaces(_ codectypes.InterfaceRegistry) { } -func (a AppModuleBasic) RegisterRESTRoutes(context client.Context, router *mux.Router) { +func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { } func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { @@ -73,7 +73,7 @@ func (a AppModuleBasic) GetQueryCmd() *cobra.Command { return cli.GetQueryCmd() } -func (a AppModuleBasic) RegisterLegacyAminoCodec(amino *codec.LegacyAmino) { +func (a AppModuleBasic) RegisterLegacyAminoCodec(_ *codec.LegacyAmino) { } type AppModule struct { @@ -103,7 +103,7 @@ func (a AppModule) ExportGenesis(ctx sdk.Context, marshaler codec.JSONCodec) jso return marshaler.MustMarshalJSON(&genState) } -func (a AppModule) RegisterInvariants(registry sdk.InvariantRegistry) { +func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { } func (a AppModule) Route() sdk.Route { @@ -114,7 +114,7 @@ func (a AppModule) QuerierRoute() string { return types.QuerierRoute } -func (a AppModule) LegacyQuerierHandler(amino *codec.LegacyAmino) sdk.Querier { +func (a AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { return nil } @@ -122,10 +122,10 @@ func (a AppModule) RegisterServices(cfg module.Configurator) { types.RegisterQueryServer(cfg.QueryServer(), NewGrpcQuerier(a.paramSpace)) } -func (a AppModule) BeginBlock(context sdk.Context, block abci.RequestBeginBlock) { +func (a AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) { } -func (a AppModule) EndBlock(context sdk.Context, block abci.RequestEndBlock) []abci.ValidatorUpdate { +func (a AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return nil } diff --git a/x/liquidity/client/testutil/cli_helpers.go b/x/liquidity/client/testutil/cli_helpers.go index 6c40bd2584e..8864dad7b96 100644 --- a/x/liquidity/client/testutil/cli_helpers.go +++ b/x/liquidity/client/testutil/cli_helpers.go @@ -35,7 +35,7 @@ func NewConfig(dbm *dbm.MemDB) network.Config { } // NewAppConstructor returns a new network AppConstructor. -func NewAppConstructor(encodingCfg params.EncodingConfig, db *dbm.MemDB) network.AppConstructor { +func NewAppConstructor(_ params.EncodingConfig, db *dbm.MemDB) network.AppConstructor { return func(val network.Validator) servertypes.Application { return GaiaApp.NewGaiaApp( val.Ctx.Logger, db, nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0, @@ -55,7 +55,7 @@ var commonArgs = []string{ // MsgCreatePoolExec creates a transaction for creating liquidity pool. func MsgCreatePoolExec(clientCtx client.Context, from, poolID, depositCoins string, - extraArgs ...string, + _ ...string, ) (testutil.BufferWriter, error) { args := append([]string{ poolID, @@ -70,7 +70,7 @@ func MsgCreatePoolExec(clientCtx client.Context, from, poolID, depositCoins stri // MsgDepositWithinBatchExec creates a transaction to deposit new amounts to the pool. func MsgDepositWithinBatchExec(clientCtx client.Context, from, poolID, depositCoins string, - extraArgs ...string, + _ ...string, ) (testutil.BufferWriter, error) { args := append([]string{ poolID, @@ -85,7 +85,7 @@ func MsgDepositWithinBatchExec(clientCtx client.Context, from, poolID, depositCo // MsgWithdrawWithinBatchExec creates a transaction to withraw pool coin amount from the pool. func MsgWithdrawWithinBatchExec(clientCtx client.Context, from, poolID, poolCoin string, - extraArgs ...string, + _ ...string, ) (testutil.BufferWriter, error) { args := append([]string{ poolID, @@ -100,7 +100,7 @@ func MsgWithdrawWithinBatchExec(clientCtx client.Context, from, poolID, poolCoin // MsgSwapWithinBatchExec creates a transaction to swap coins in the pool. func MsgSwapWithinBatchExec(clientCtx client.Context, from, poolID, swapTypeID, - offerCoin, demandCoinDenom, orderPrice, swapFeeRate string, extraArgs ...string, + offerCoin, demandCoinDenom, orderPrice, swapFeeRate string, _ ...string, ) (testutil.BufferWriter, error) { args := append([]string{ poolID, diff --git a/x/liquidity/keeper/grpc_query.go b/x/liquidity/keeper/grpc_query.go index e15b0227c0d..85e39bedc56 100644 --- a/x/liquidity/keeper/grpc_query.go +++ b/x/liquidity/keeper/grpc_query.go @@ -298,7 +298,7 @@ func (k Querier) PoolBatchWithdrawMsgs(c context.Context, req *types.QueryPoolBa } // Params queries params of liquidity module. -func (k Querier) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { +func (k Querier) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { ctx := sdk.UnwrapSDKContext(c) params := k.GetParams(ctx) diff --git a/x/liquidity/keeper/invariants.go b/x/liquidity/keeper/invariants.go index 251b6f15bf2..4daa0675c3e 100644 --- a/x/liquidity/keeper/invariants.go +++ b/x/liquidity/keeper/invariants.go @@ -243,7 +243,7 @@ func SwapMatchingInvariants(xToY, yToX []*types.SwapMsgState, matchResultXtoY, m } // SwapPriceInvariants checks swap price invariants. -func SwapPriceInvariants(matchResultXtoY, matchResultYtoX []types.MatchResult, poolXDelta, poolYDelta, poolXDelta2, poolYDelta2 sdk.Dec, result types.BatchResult) { +func SwapPriceInvariants(matchResultXtoY, matchResultYtoX []types.MatchResult, _, _, poolXDelta2, poolYDelta2 sdk.Dec, result types.BatchResult) { invariantCheckX := sdk.ZeroDec() invariantCheckY := sdk.ZeroDec() diff --git a/x/liquidity/module.go b/x/liquidity/module.go index 577372b1895..2acdd799fb7 100644 --- a/x/liquidity/module.go +++ b/x/liquidity/module.go @@ -52,7 +52,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { } // ValidateGenesis performs genesis state validation for the liquidity module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config sdkclient.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ sdkclient.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -62,7 +62,7 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config sdkclient.TxEn } // RegisterRESTRoutes registers the REST routes for the liquidity module. -func (AppModuleBasic) RegisterRESTRoutes(clientCtx sdkclient.Context, rtr *mux.Router) { +func (AppModuleBasic) RegisterRESTRoutes(_ sdkclient.Context, _ *mux.Router) { } // GetTxCmd returns the root tx command for the liquidity module. @@ -182,7 +182,7 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { } // ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { +func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { return nil } diff --git a/x/liquidity/simulation/genesis.go b/x/liquidity/simulation/genesis.go index f2fa467ec8b..fd4d994a3fb 100644 --- a/x/liquidity/simulation/genesis.go +++ b/x/liquidity/simulation/genesis.go @@ -29,7 +29,7 @@ const ( ) // GenLiquidityPoolTypes return default PoolType temporarily, It will be randomized in the liquidity v2 -func GenLiquidityPoolTypes(r *rand.Rand) (liquidityPoolTypes []types.PoolType) { +func GenLiquidityPoolTypes(_ *rand.Rand) (liquidityPoolTypes []types.PoolType) { return types.DefaultPoolTypes } diff --git a/x/liquidity/simulation/operations_test.go b/x/liquidity/simulation/operations_test.go index 5443874a11e..36ead8927f5 100644 --- a/x/liquidity/simulation/operations_test.go +++ b/x/liquidity/simulation/operations_test.go @@ -194,7 +194,7 @@ func createTestApp(isCheckTx bool) (*lapp.GaiaApp, sdk.Context) { return app, ctx } -func getTestingAccounts(t *testing.T, r *rand.Rand, app *lapp.GaiaApp, ctx sdk.Context, n int) []simtypes.Account { +func getTestingAccounts(_ *testing.T, r *rand.Rand, app *lapp.GaiaApp, ctx sdk.Context, n int) []simtypes.Account { accounts := simtypes.RandomAccounts(r, n) initAmt := sdk.TokensFromConsensusPower(1_000_000, sdk.DefaultPowerReduction) diff --git a/x/liquidity/simulation/params.go b/x/liquidity/simulation/params.go index bf99c81863d..80058a32cd5 100644 --- a/x/liquidity/simulation/params.go +++ b/x/liquidity/simulation/params.go @@ -14,7 +14,7 @@ import ( // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation -func ParamChanges(r *rand.Rand) []simtypes.ParamChange { +func ParamChanges(_ *rand.Rand) []simtypes.ParamChange { return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, string(types.KeyMinInitDepositAmount), func(r *rand.Rand) string { diff --git a/x/liquidity/types/swap.go b/x/liquidity/types/swap.go index a267c1e56c4..423dfba1016 100644 --- a/x/liquidity/types/swap.go +++ b/x/liquidity/types/swap.go @@ -453,7 +453,7 @@ func CheckSwapPrice(matchResultXtoY, matchResultYtoX []MatchResult, swapPrice sd } // Find matched orders and set status for msgs -func FindOrderMatch(direction OrderDirection, swapMsgStates []*SwapMsgState, executableAmt, swapPrice sdk.Dec, height int64) ( +func FindOrderMatch(direction OrderDirection, swapMsgStates []*SwapMsgState, executableAmt, swapPrice sdk.Dec, _ int64) ( matchResults []MatchResult, poolXDelta, poolYDelta sdk.Dec, ) { poolXDelta = sdk.ZeroDec() From d803572303f01367d160556ef7f352f18965ca4f Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Thu, 20 Apr 2023 16:23:28 +0700 Subject: [PATCH 04/24] ineffectual assignments --- x/liquidity/types/swap_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x/liquidity/types/swap_test.go b/x/liquidity/types/swap_test.go index 95bcb5774dd..6195424caf9 100644 --- a/x/liquidity/types/swap_test.go +++ b/x/liquidity/types/swap_test.go @@ -51,9 +51,9 @@ func TestSwapScenario(t *testing.T) { xOrderAddrs := addrs[1:2] yOrderAddrs := addrs[2:3] _, batch := app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) - _, batch = app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) - _, batch = app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) - _, batch = app.TestSwapPool(t, simapp, ctx, yOfferCoins, yOrderPrices, yOrderAddrs, poolID, false) + _, _ = app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + _, _ = app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) + _, _ = app.TestSwapPool(t, simapp, ctx, yOfferCoins, yOrderPrices, yOrderAddrs, poolID, false) // Set the execution status flag of messages to true. msgs := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, batch) @@ -246,8 +246,8 @@ func TestMaxOrderRatio(t *testing.T) { require.NoError(t, err) // Success case, same GetMaxOrderRatio orders - offerCoin = sdk.NewCoin(denomX, X.ToDec().Mul(maxOrderRatio).TruncateInt().AddRaw(1)) - offerCoinY = sdk.NewCoin(denomY, Y.ToDec().Mul(maxOrderRatio).TruncateInt().AddRaw(1)) + _ = sdk.NewCoin(denomX, X.ToDec().Mul(maxOrderRatio).TruncateInt().AddRaw(1)) + _ = sdk.NewCoin(denomY, Y.ToDec().Mul(maxOrderRatio).TruncateInt().AddRaw(1)) offerCoin = sdk.NewCoin(denomX, params.MinInitDepositAmount.Quo(sdk.NewInt(2))) offerCoinY = sdk.NewCoin(denomY, params.MinInitDepositAmount.Quo(sdk.NewInt(10))) From 4c695a01685b22c40b6c879ebc7ffa2d08cc12bf Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Thu, 20 Apr 2023 16:27:36 +0700 Subject: [PATCH 05/24] ineffetual assignments --- tests/e2e/e2e_globalfee_proposal_test.go | 2 +- x/liquidity/keeper/batch_test.go | 18 +++++++++--------- x/liquidity/keeper/invariants_test.go | 2 +- x/liquidity/keeper/liquidity_pool_test.go | 13 ++++++++----- x/liquidity/keeper/store_test.go | 4 ++-- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/tests/e2e/e2e_globalfee_proposal_test.go b/tests/e2e/e2e_globalfee_proposal_test.go index 8c4063171e9..a36158d4450 100644 --- a/tests/e2e/e2e_globalfee_proposal_test.go +++ b/tests/e2e/e2e_globalfee_proposal_test.go @@ -10,7 +10,7 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) -func (s *IntegrationTestSuite) govProposeNewGlobalfee(newGlobalfee sdk.DecCoins, proposalCounter int, submitter string, _ string) { //nolint:unparam +func (s *IntegrationTestSuite) govProposeNewGlobalfee(newGlobalfee sdk.DecCoins, proposalCounter int, submitter string, _ string) { s.writeGovParamChangeProposalGlobalFees(s.chainA, newGlobalfee) chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) submitGovFlags := []string{"param-change", configFile(proposalGlobalFeeFilename)} diff --git a/x/liquidity/keeper/batch_test.go b/x/liquidity/keeper/batch_test.go index 5ec51d34bd0..c5336087790 100644 --- a/x/liquidity/keeper/batch_test.go +++ b/x/liquidity/keeper/batch_test.go @@ -320,8 +320,8 @@ func TestCreateDepositWithdrawWithinBatch(t *testing.T) { require.Equal(t, uint64(2), batch.Index) // withdraw - withdrawerBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) - withdrawerBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + _ = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + _ = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) withdrawerBalancePoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) moduleAccEscrowAmtPool := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, pools[0].PoolCoinDenom) require.Equal(t, sdk.ZeroInt(), moduleAccEscrowAmtPool.Amount) @@ -329,8 +329,8 @@ func TestCreateDepositWithdrawWithinBatch(t *testing.T) { _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) require.NoError(t, err) - withdrawerBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) - withdrawerBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + withdrawerBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + withdrawerBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) withdrawerBalancePoolCoin := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) require.Equal(t, sdk.ZeroInt(), withdrawerBalanceX.Amount) @@ -497,8 +497,8 @@ func TestCreateDepositWithdrawWithinBatch2(t *testing.T) { require.Equal(t, uint64(2), batch.Index) // withdraw - withdrawerBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) - withdrawerBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + _ = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + _ = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) withdrawerBalancePoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) moduleAccEscrowAmtPool := simapp.BankKeeper.GetBalance(ctx, moduleAccAddress, pools[0].PoolCoinDenom) require.Equal(t, sdk.ZeroInt(), moduleAccEscrowAmtPool.Amount) @@ -506,8 +506,8 @@ func TestCreateDepositWithdrawWithinBatch2(t *testing.T) { _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) require.NoError(t, err) - withdrawerBalanceX = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) - withdrawerBalanceY = simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) + withdrawerBalanceX := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[0]) + withdrawerBalanceY := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].ReserveCoinDenoms[1]) withdrawerBalancePoolCoin := simapp.BankKeeper.GetBalance(ctx, addrs[1], pools[0].PoolCoinDenom) poolCoin = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) require.Equal(t, sdk.ZeroInt(), withdrawerBalanceX.Amount) @@ -760,7 +760,7 @@ func TestDepositRefundDeletedPool(t *testing.T) { // delete previously created pool simapp.LiquidityKeeper.DeletePool(ctx, pool) - pool, found = simapp.LiquidityKeeper.GetPool(ctx, poolID) + _, found = simapp.LiquidityKeeper.GetPool(ctx, poolID) require.False(t, found) liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) diff --git a/x/liquidity/keeper/invariants_test.go b/x/liquidity/keeper/invariants_test.go index 49625ee302a..2ad3a62ded4 100644 --- a/x/liquidity/keeper/invariants_test.go +++ b/x/liquidity/keeper/invariants_test.go @@ -136,7 +136,7 @@ func TestLiquidityPoolsEscrowAmountInvariant(t *testing.T) { err := simapp.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addrs[0], sdk.NewCoins(sdk.NewCoin(xOfferCoins[0].Denom, xOfferCoins[0].Amount.QuoRaw(2)))) require.NoError(t, err) - escrowAmt = simapp.BankKeeper.GetAllBalances(ctx, batchEscrowAcc) + _ = simapp.BankKeeper.GetAllBalances(ctx, batchEscrowAcc) msg, broken := invariant(ctx) require.True(t, broken) diff --git a/x/liquidity/keeper/liquidity_pool_test.go b/x/liquidity/keeper/liquidity_pool_test.go index fb90c79a3a8..584054b5fa0 100644 --- a/x/liquidity/keeper/liquidity_pool_test.go +++ b/x/liquidity/keeper/liquidity_pool_test.go @@ -694,6 +694,7 @@ func TestReserveAccManipulation(t *testing.T) { createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) + require.NoError(t, err) pools := simapp.LiquidityKeeper.GetAllPools(ctx) pool := pools[0] @@ -706,25 +707,25 @@ func TestReserveAccManipulation(t *testing.T) { metadata := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pool) require.Equal(t, depositA.Add(manipulationReserveA1).Amount, metadata.ReserveCoins.AmountOf(denomA)) - poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + _ = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, withdrawerPoolCoinBefore.Amount.QuoRaw(2))) simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) poolBatch, _ := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) - msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + _ = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) // send coin to manipulate reserve account simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA2)) simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveOther)) - reserveAccBalances = simapp.BankKeeper.GetAllBalances(ctx, reserveAcc) + _ = simapp.BankKeeper.GetAllBalances(ctx, reserveAcc) metadata = simapp.LiquidityKeeper.GetPoolMetaData(ctx, pool) require.NotEqual(t, manipulationReserveOther, metadata.ReserveCoins.AmountOf(sdk.DefaultBondDenom)) // Case for withdrawing all reserve coins after manipulation - poolCoinBefore = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) + poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) withdrawerPoolCoinBefore = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) withdrawMsg = types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) @@ -732,7 +733,7 @@ func TestReserveAccManipulation(t *testing.T) { require.NoError(t, err) poolBatch, _ = simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) - msgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) + msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch) require.NoError(t, err) @@ -1157,6 +1158,8 @@ func TestOverflowAndZeroCases(t *testing.T) { depositMsg := types.NewMsgDepositWithinBatch(addrs[0], pools[0].Id, hugeCoins) depositMsg2 := types.NewMsgDepositWithinBatch(addrs[0], pools[0].Id, hugeCoins2) _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) + require.NoError(t, err) + _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg2) require.NoError(t, err) diff --git a/x/liquidity/keeper/store_test.go b/x/liquidity/keeper/store_test.go index fa9f118167b..cd0e7603804 100644 --- a/x/liquidity/keeper/store_test.go +++ b/x/liquidity/keeper/store_test.go @@ -55,7 +55,7 @@ func TestGetAllLiquidityPoolBatchSwapMsgs(t *testing.T) { pool, found := simapp.LiquidityKeeper.GetPool(ctx, poolID) require.True(t, found) - poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + poolBatch, _ := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) require.Equal(t, uint64(1), poolBatch.SwapMsgIndex) for i, msg := range xToY { @@ -94,7 +94,7 @@ func TestGetAllLiquidityPoolBatchSwapMsgs(t *testing.T) { msgs = simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, poolBatch) require.Equal(t, 10, len(msgs)) - poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + poolBatch, _ = simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) require.Equal(t, uint64(21), poolBatch.SwapMsgIndex) poolBatch.SwapMsgIndex = uint64(18446744073709551610) From 5f34fa2d7a234842b9b2eb2d1bf6276578f0bb34 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Thu, 20 Apr 2023 16:30:51 +0700 Subject: [PATCH 06/24] correct variable names --- tests/e2e/e2e_globalfee_proposal_test.go | 2 +- x/liquidity/keeper/keeper_test.go | 1 - x/liquidity/simulation/operations_test.go | 4 ++-- x/liquidity/types/msgs_test.go | 17 +++++++++-------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/e2e/e2e_globalfee_proposal_test.go b/tests/e2e/e2e_globalfee_proposal_test.go index a36158d4450..6da9b4575db 100644 --- a/tests/e2e/e2e_globalfee_proposal_test.go +++ b/tests/e2e/e2e_globalfee_proposal_test.go @@ -10,7 +10,7 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) -func (s *IntegrationTestSuite) govProposeNewGlobalfee(newGlobalfee sdk.DecCoins, proposalCounter int, submitter string, _ string) { +func (s *IntegrationTestSuite) govProposeNewGlobalfee(newGlobalfee sdk.DecCoins, proposalCounter int, submitter string, _ string) { s.writeGovParamChangeProposalGlobalFees(s.chainA, newGlobalfee) chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) submitGovFlags := []string{"param-change", configFile(proposalGlobalFeeFilename)} diff --git a/x/liquidity/keeper/keeper_test.go b/x/liquidity/keeper/keeper_test.go index 19ba696af36..34b95f64178 100644 --- a/x/liquidity/keeper/keeper_test.go +++ b/x/liquidity/keeper/keeper_test.go @@ -23,7 +23,6 @@ type KeeperTestSuite struct { batches []types.PoolBatch depositMsgs []types.DepositMsgState withdrawMsgs []types.WithdrawMsgState - swapMsgs []types.SwapMsgState queryClient types.QueryClient } diff --git a/x/liquidity/simulation/operations_test.go b/x/liquidity/simulation/operations_test.go index 36ead8927f5..613848f1124 100644 --- a/x/liquidity/simulation/operations_test.go +++ b/x/liquidity/simulation/operations_test.go @@ -184,7 +184,7 @@ func TestSimulateMsgSwapWithinBatch(t *testing.T) { require.Len(t, futureOperations, 0) } -func createTestApp(isCheckTx bool) (*lapp.GaiaApp, sdk.Context) { +func createTestApp(isCheckTx bool) (*lapp.GaiaApp, sdk.Context) { //nolint:unparam app := lapp.Setup(false) ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{}) @@ -194,7 +194,7 @@ func createTestApp(isCheckTx bool) (*lapp.GaiaApp, sdk.Context) { return app, ctx } -func getTestingAccounts(_ *testing.T, r *rand.Rand, app *lapp.GaiaApp, ctx sdk.Context, n int) []simtypes.Account { +func getTestingAccounts(_ *testing.T, r *rand.Rand, app *lapp.GaiaApp, ctx sdk.Context, n int) []simtypes.Account { //nolint:unparam accounts := simtypes.RandomAccounts(r, n) initAmt := sdk.TokensFromConsensusPower(1_000_000, sdk.DefaultPowerReduction) diff --git a/x/liquidity/types/msgs_test.go b/x/liquidity/types/msgs_test.go index 67d6e660cfe..ee42ae73afe 100644 --- a/x/liquidity/types/msgs_test.go +++ b/x/liquidity/types/msgs_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/gaia/v9/x/liquidity/types" ) +//nolint:revive // these variable names aren't worth changing right now const ( DefaultPoolTypeId = uint32(1) DefaultPoolId = uint64(1) @@ -217,7 +218,7 @@ func TestMsgPanics(t *testing.T) { } func TestMsgValidateBasic(t *testing.T) { - validPoolTypeId := DefaultPoolTypeId + validPoolTypeID := DefaultPoolTypeId validAddr := sdk.AccAddress(crypto.AddressHash([]byte("testAccount"))).String() validCoin := sdk.NewCoin(DenomY, sdk.NewInt(10000)) @@ -244,17 +245,17 @@ func TestMsgValidateBasic(t *testing.T) { types.ErrBadPoolTypeID.Error(), }, { - types.MsgCreatePool{PoolTypeId: validPoolTypeId}, + types.MsgCreatePool{PoolTypeId: validPoolTypeID}, types.ErrInvalidPoolCreatorAddr.Error(), }, { - types.MsgCreatePool{PoolCreatorAddress: validAddr, PoolTypeId: validPoolTypeId}, + types.MsgCreatePool{PoolCreatorAddress: validAddr, PoolTypeId: validPoolTypeID}, types.ErrNumOfReserveCoin.Error(), }, { types.MsgCreatePool{ PoolCreatorAddress: validAddr, - PoolTypeId: validPoolTypeId, + PoolTypeId: validPoolTypeID, DepositCoins: coinsWithInvalidDenom, }, invalidDenomErrMsg, @@ -262,7 +263,7 @@ func TestMsgValidateBasic(t *testing.T) { { types.MsgCreatePool{ PoolCreatorAddress: validAddr, - PoolTypeId: validPoolTypeId, + PoolTypeId: validPoolTypeID, DepositCoins: coinsWithNegative, }, negativeCoinErrMsg, @@ -270,7 +271,7 @@ func TestMsgValidateBasic(t *testing.T) { { types.MsgCreatePool{ PoolCreatorAddress: validAddr, - PoolTypeId: validPoolTypeId, + PoolTypeId: validPoolTypeID, DepositCoins: coinsWithZero, }, zeroCoinErrMsg, @@ -278,7 +279,7 @@ func TestMsgValidateBasic(t *testing.T) { { types.MsgCreatePool{ PoolCreatorAddress: validAddr, - PoolTypeId: validPoolTypeId, + PoolTypeId: validPoolTypeID, DepositCoins: sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(int64(types.MinReserveCoinNum)-1))), }, types.ErrNumOfReserveCoin.Error(), @@ -286,7 +287,7 @@ func TestMsgValidateBasic(t *testing.T) { { types.MsgCreatePool{ PoolCreatorAddress: validAddr, - PoolTypeId: validPoolTypeId, + PoolTypeId: validPoolTypeID, DepositCoins: sdk.NewCoins(sdk.NewCoin(DenomX, sdk.NewInt(int64(types.MaxReserveCoinNum)+1))), }, types.ErrNumOfReserveCoin.Error(), From e57bfc89be2674b80b0c5c696a9b15c27d81018b Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Thu, 20 Apr 2023 18:46:38 +0700 Subject: [PATCH 07/24] lint --- x/liquidity/keeper/swap_test.go | 4 ++-- x/liquidity/module.go | 4 ++-- x/liquidity/types/swap_test.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x/liquidity/keeper/swap_test.go b/x/liquidity/keeper/swap_test.go index 836535d71da..be2228e084d 100644 --- a/x/liquidity/keeper/swap_test.go +++ b/x/liquidity/keeper/swap_test.go @@ -138,7 +138,7 @@ func TestSwapExecution(t *testing.T) { } } -func testSwapEdgeCases(t *testing.T, r *rand.Rand, simapp *app.GaiaApp, ctx sdk.Context, X, Y sdk.Int, depositBalance sdk.Coins, addrs []sdk.AccAddress) { +func testSwapEdgeCases(t *testing.T, r *rand.Rand, simapp *app.GaiaApp, ctx sdk.Context, x, y sdk.Int, depositBalance sdk.Coins, addrs []sdk.AccAddress) { // simapp, ctx := createTestInput() simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) params := simapp.LiquidityKeeper.GetParams(ctx) @@ -168,7 +168,7 @@ func testSwapEdgeCases(t *testing.T, r *rand.Rand, simapp *app.GaiaApp, ctx sdk. remainingSwapMsgs := simapp.LiquidityKeeper.GetAllNotProcessedPoolBatchSwapMsgStates(ctx, batch) if ctx.BlockHeight() == 0 || len(remainingSwapMsgs) == 0 { // make random orders, set buyer, seller accounts for the orders - xToY, yToX = app.GetRandomSizeOrders(denomX, denomY, X, Y, r, 100, 100) + xToY, yToX = app.GetRandomSizeOrders(denomX, denomY, x, y, r, 100, 100) buyerAddrs := app.AddTestAddrsIncremental(simapp, ctx, len(xToY), sdk.NewInt(0)) sellerAddrs := app.AddTestAddrsIncremental(simapp, ctx, len(yToX), sdk.NewInt(0)) diff --git a/x/liquidity/module.go b/x/liquidity/module.go index 2acdd799fb7..5996247d6a9 100644 --- a/x/liquidity/module.go +++ b/x/liquidity/module.go @@ -82,7 +82,7 @@ func (a AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the liquidity module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux *runtime.ServeMux) { - types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + _ = types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) } // RegisterServices registers module services. @@ -91,7 +91,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { querier := keeper.Querier{Keeper: am.keeper} types.RegisterQueryServer(cfg.QueryServer(), querier) m := keeper.NewMigrator(am.keeper) - cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2) + _ = cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2) } // AppModule implements an application module for the liquidity module. diff --git a/x/liquidity/types/swap_test.go b/x/liquidity/types/swap_test.go index 6195424caf9..3c1e5cf2c85 100644 --- a/x/liquidity/types/swap_test.go +++ b/x/liquidity/types/swap_test.go @@ -535,8 +535,8 @@ func TestCalculateNoMatchEdgeCase(t *testing.T) { func TestMakeOrderMapEdgeCase(t *testing.T) { onlyNotMatched := false var swapMsgs []*types.SwapMsgState - swapMsgsJson := `[{"msg_index":1,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"19228500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"19228500"},"demand_coin_denom":"denomY","order_price":"0.027506527499265415"}},{"msg_index":2,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":3,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"23501500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"23501500"},"demand_coin_denom":"denomY","order_price":"0.027616663745508720"}},{"msg_index":4,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"200831000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"200831000"},"demand_coin_denom":"denomY","order_price":"0.027589129683947893"}},{"msg_index":5,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"160237500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"160237500"},"demand_coin_denom":"denomY","order_price":"0.027313789068339631"}},{"msg_index":6,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"175193000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"175193000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":7,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"183739000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"183739000"},"demand_coin_denom":"denomY","order_price":"0.027699265930191198"}},{"msg_index":8,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"32047500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"32047500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":9,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"111098000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"111098000"},"demand_coin_denom":"denomY","order_price":"0.027286255006778805"}},{"msg_index":10,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"166647000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"166647000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":11,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"98279000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"98279000"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":12,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"8546000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"8546000"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":13,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"87596500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"87596500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":14,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"111098000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"111098000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":15,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"38457000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"38457000"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":16,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"153828000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"153828000"},"demand_coin_denom":"denomY","order_price":"0.027616663745508720"}},{"msg_index":17,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"70504500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"70504500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":18,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"47003000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"47003000"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":19,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"132463000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"132463000"},"demand_coin_denom":"denomY","order_price":"0.027726799991752025"}},{"msg_index":20,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"66231500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"66231500"},"demand_coin_denom":"denomY","order_price":"0.027561595622387067"}},{"msg_index":21,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"119644000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"119644000"},"demand_coin_denom":"denomY","order_price":"0.027506527499265415"}},{"msg_index":22,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"17092000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"17092000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":23,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"209377000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"209377000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":24,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"207240500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"207240500"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":25,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"155964500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"155964500"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":26,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"194421500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"194421500"},"demand_coin_denom":"denomY","order_price":"0.027286255006778805"}},{"msg_index":27,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"102552000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"102552000"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":28,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"151691500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"151691500"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":29,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"113234500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"113234500"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":30,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"117507500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"117507500"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":31,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":32,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"200831000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"200831000"},"demand_coin_denom":"denomY","order_price":"0.027534061560826241"}},{"msg_index":33,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027726799991752025"}},{"msg_index":34,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"98279000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"98279000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":35,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"76914000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf58c6rp0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"76914000"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":36,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"23501500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf46wwkua","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"23501500"},"demand_coin_denom":"denomY","order_price":"0.027754334053312851"}},{"msg_index":37,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4733282800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4733282800"},"demand_coin_denom":"denomX","order_price":"0.027699265930191198"}},{"msg_index":38,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3957334800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3957334800"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":39,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2483033600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2483033600"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":40,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5509230800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5509230800"},"demand_coin_denom":"denomX","order_price":"0.027561595622387067"}},{"msg_index":41,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2327844000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2327844000"},"demand_coin_denom":"denomX","order_price":"0.027423925314582936"}},{"msg_index":42,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4733282800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4733282800"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":43,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7061126800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7061126800"},"demand_coin_denom":"denomX","order_price":"0.027726799991752025"}},{"msg_index":44,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4655688000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4655688000"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":45,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3026197200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3026197200"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":46,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7293911200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7293911200"},"demand_coin_denom":"denomX","order_price":"0.027616663745508720"}},{"msg_index":47,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4810877600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4810877600"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":48,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4345308800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4345308800"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":49,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5509230800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5509230800"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":50,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4190119200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4190119200"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":51,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"543163600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"543163600"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":52,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4578093200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4578093200"},"demand_coin_denom":"denomX","order_price":"0.027506527499265415"}},{"msg_index":53,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6517963200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6517963200"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":54,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4190119200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4190119200"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":55,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1939870000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1939870000"},"demand_coin_denom":"denomX","order_price":"0.027754334053312851"}},{"msg_index":56,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1163922000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1163922000"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":57,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5897204800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5897204800"},"demand_coin_denom":"denomX","order_price":"0.027644197807069546"}},{"msg_index":58,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"155189600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"155189600"},"demand_coin_denom":"denomX","order_price":"0.027671731868630372"}},{"msg_index":59,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2250249200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2250249200"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":60,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2948602400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2948602400"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":61,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7449100800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7449100800"},"demand_coin_denom":"denomX","order_price":"0.027313789068339631"}},{"msg_index":62,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6129989200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6129989200"},"demand_coin_denom":"denomX","order_price":"0.027341323129900457"}},{"msg_index":63,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3491766000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3491766000"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":64,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6362773600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6362773600"},"demand_coin_denom":"denomX","order_price":"0.027726799991752025"}},{"msg_index":65,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7138721600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7138721600"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":66,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3724550400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3724550400"},"demand_coin_denom":"denomX","order_price":"0.027616663745508720"}},{"msg_index":67,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3103792000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3103792000"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":68,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"232784400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"232784400"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":69,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6052394400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6052394400"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":70,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5121256800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5121256800"},"demand_coin_denom":"denomX","order_price":"0.027644197807069546"}}]` - json.Unmarshal([]byte(swapMsgsJson), &swapMsgs) + swapMsgsJSON := `[{"msg_index":1,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"19228500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"19228500"},"demand_coin_denom":"denomY","order_price":"0.027506527499265415"}},{"msg_index":2,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":3,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"23501500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"23501500"},"demand_coin_denom":"denomY","order_price":"0.027616663745508720"}},{"msg_index":4,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"200831000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"200831000"},"demand_coin_denom":"denomY","order_price":"0.027589129683947893"}},{"msg_index":5,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"160237500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"160237500"},"demand_coin_denom":"denomY","order_price":"0.027313789068339631"}},{"msg_index":6,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"175193000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"175193000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":7,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"183739000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"183739000"},"demand_coin_denom":"denomY","order_price":"0.027699265930191198"}},{"msg_index":8,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"32047500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"32047500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":9,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"111098000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"111098000"},"demand_coin_denom":"denomY","order_price":"0.027286255006778805"}},{"msg_index":10,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"166647000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"166647000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":11,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"98279000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"98279000"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":12,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"8546000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"8546000"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":13,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"87596500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"87596500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":14,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"111098000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"111098000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":15,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"38457000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"38457000"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":16,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"153828000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"153828000"},"demand_coin_denom":"denomY","order_price":"0.027616663745508720"}},{"msg_index":17,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"70504500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"70504500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":18,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"47003000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"47003000"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":19,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"132463000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"132463000"},"demand_coin_denom":"denomY","order_price":"0.027726799991752025"}},{"msg_index":20,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"66231500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"66231500"},"demand_coin_denom":"denomY","order_price":"0.027561595622387067"}},{"msg_index":21,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"119644000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"119644000"},"demand_coin_denom":"denomY","order_price":"0.027506527499265415"}},{"msg_index":22,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"17092000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"17092000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":23,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"209377000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"209377000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":24,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"207240500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"207240500"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":25,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"155964500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"155964500"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":26,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"194421500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"194421500"},"demand_coin_denom":"denomY","order_price":"0.027286255006778805"}},{"msg_index":27,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"102552000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"102552000"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":28,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"151691500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"151691500"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":29,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"113234500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"113234500"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":30,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"117507500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"117507500"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":31,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":32,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"200831000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"200831000"},"demand_coin_denom":"denomY","order_price":"0.027534061560826241"}},{"msg_index":33,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027726799991752025"}},{"msg_index":34,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"98279000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"98279000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":35,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"76914000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf58c6rp0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"76914000"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":36,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"23501500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf46wwkua","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"23501500"},"demand_coin_denom":"denomY","order_price":"0.027754334053312851"}},{"msg_index":37,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4733282800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4733282800"},"demand_coin_denom":"denomX","order_price":"0.027699265930191198"}},{"msg_index":38,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3957334800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3957334800"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":39,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2483033600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2483033600"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":40,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5509230800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5509230800"},"demand_coin_denom":"denomX","order_price":"0.027561595622387067"}},{"msg_index":41,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2327844000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2327844000"},"demand_coin_denom":"denomX","order_price":"0.027423925314582936"}},{"msg_index":42,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4733282800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4733282800"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":43,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7061126800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7061126800"},"demand_coin_denom":"denomX","order_price":"0.027726799991752025"}},{"msg_index":44,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4655688000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4655688000"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":45,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3026197200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3026197200"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":46,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7293911200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7293911200"},"demand_coin_denom":"denomX","order_price":"0.027616663745508720"}},{"msg_index":47,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4810877600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4810877600"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":48,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4345308800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4345308800"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":49,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5509230800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5509230800"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":50,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4190119200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4190119200"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":51,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"543163600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"543163600"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":52,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4578093200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4578093200"},"demand_coin_denom":"denomX","order_price":"0.027506527499265415"}},{"msg_index":53,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6517963200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6517963200"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":54,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4190119200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4190119200"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":55,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1939870000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1939870000"},"demand_coin_denom":"denomX","order_price":"0.027754334053312851"}},{"msg_index":56,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1163922000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1163922000"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":57,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5897204800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5897204800"},"demand_coin_denom":"denomX","order_price":"0.027644197807069546"}},{"msg_index":58,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"155189600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"155189600"},"demand_coin_denom":"denomX","order_price":"0.027671731868630372"}},{"msg_index":59,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2250249200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2250249200"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":60,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2948602400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2948602400"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":61,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7449100800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7449100800"},"demand_coin_denom":"denomX","order_price":"0.027313789068339631"}},{"msg_index":62,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6129989200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6129989200"},"demand_coin_denom":"denomX","order_price":"0.027341323129900457"}},{"msg_index":63,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3491766000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3491766000"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":64,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6362773600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6362773600"},"demand_coin_denom":"denomX","order_price":"0.027726799991752025"}},{"msg_index":65,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7138721600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7138721600"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":66,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3724550400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3724550400"},"demand_coin_denom":"denomX","order_price":"0.027616663745508720"}},{"msg_index":67,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3103792000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3103792000"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":68,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"232784400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"232784400"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":69,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6052394400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6052394400"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":70,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5121256800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5121256800"},"demand_coin_denom":"denomX","order_price":"0.027644197807069546"}}]` + json.Unmarshal([]byte(swapMsgsJSON), &swapMsgs) orderMap, xToY, yToX := types.MakeOrderMap(swapMsgs, DenomX, DenomY, onlyNotMatched) require.NotZero(t, len(orderMap)) require.NotNil(t, xToY) From 6e0beaa5edb8a07b8096eb488741eb7991b9cd93 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Thu, 20 Apr 2023 18:48:39 +0700 Subject: [PATCH 08/24] lint the swap test --- x/liquidity/keeper/swap_test.go | 4 ++-- x/liquidity/types/swap_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x/liquidity/keeper/swap_test.go b/x/liquidity/keeper/swap_test.go index be2228e084d..b255fbcbf3a 100644 --- a/x/liquidity/keeper/swap_test.go +++ b/x/liquidity/keeper/swap_test.go @@ -347,10 +347,10 @@ func TestSwapWithDepletedPool(t *testing.T) { liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) } -func createPool(simapp *app.GaiaApp, ctx sdk.Context, X, Y sdk.Int, denomX, denomY string) (types.Pool, error) { +func createPool(simapp *app.GaiaApp, ctx sdk.Context, x, y sdk.Int, denomX, denomY string) (types.Pool, error) { params := simapp.LiquidityKeeper.GetParams(ctx) - coins := sdk.NewCoins(sdk.NewCoin(denomX, X), sdk.NewCoin(denomY, Y)) + coins := sdk.NewCoins(sdk.NewCoin(denomX, x), sdk.NewCoin(denomY, y)) addr := app.AddRandomTestAddr(simapp, ctx, coins.Add(params.PoolCreationFee...)) return simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(addr, types.DefaultPoolTypeID, coins)) diff --git a/x/liquidity/types/swap_test.go b/x/liquidity/types/swap_test.go index 3c1e5cf2c85..365058e8cae 100644 --- a/x/liquidity/types/swap_test.go +++ b/x/liquidity/types/swap_test.go @@ -536,7 +536,7 @@ func TestMakeOrderMapEdgeCase(t *testing.T) { onlyNotMatched := false var swapMsgs []*types.SwapMsgState swapMsgsJSON := `[{"msg_index":1,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"19228500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"19228500"},"demand_coin_denom":"denomY","order_price":"0.027506527499265415"}},{"msg_index":2,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":3,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"23501500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"23501500"},"demand_coin_denom":"denomY","order_price":"0.027616663745508720"}},{"msg_index":4,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"200831000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"200831000"},"demand_coin_denom":"denomY","order_price":"0.027589129683947893"}},{"msg_index":5,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"160237500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"160237500"},"demand_coin_denom":"denomY","order_price":"0.027313789068339631"}},{"msg_index":6,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"175193000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"175193000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":7,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"183739000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"183739000"},"demand_coin_denom":"denomY","order_price":"0.027699265930191198"}},{"msg_index":8,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"32047500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"32047500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":9,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"111098000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"111098000"},"demand_coin_denom":"denomY","order_price":"0.027286255006778805"}},{"msg_index":10,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"166647000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"166647000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":11,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"98279000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"98279000"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":12,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"8546000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"8546000"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":13,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"87596500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"87596500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":14,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"111098000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"111098000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":15,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"38457000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"38457000"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":16,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"153828000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"153828000"},"demand_coin_denom":"denomY","order_price":"0.027616663745508720"}},{"msg_index":17,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"70504500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"70504500"},"demand_coin_denom":"denomY","order_price":"0.027451459376143762"}},{"msg_index":18,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"47003000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"47003000"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":19,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"132463000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"132463000"},"demand_coin_denom":"denomY","order_price":"0.027726799991752025"}},{"msg_index":20,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"66231500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"66231500"},"demand_coin_denom":"denomY","order_price":"0.027561595622387067"}},{"msg_index":21,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"119644000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"119644000"},"demand_coin_denom":"denomY","order_price":"0.027506527499265415"}},{"msg_index":22,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"17092000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"17092000"},"demand_coin_denom":"denomY","order_price":"0.027341323129900457"}},{"msg_index":23,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"209377000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"209377000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":24,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"207240500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"207240500"},"demand_coin_denom":"denomY","order_price":"0.027396391253022110"}},{"msg_index":25,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"155964500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"155964500"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":26,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"194421500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"194421500"},"demand_coin_denom":"denomY","order_price":"0.027286255006778805"}},{"msg_index":27,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"102552000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"102552000"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":28,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"151691500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"151691500"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":29,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"113234500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"113234500"},"demand_coin_denom":"denomY","order_price":"0.027368857191461284"}},{"msg_index":30,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"117507500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"117507500"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":31,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":32,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"200831000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"200831000"},"demand_coin_denom":"denomY","order_price":"0.027534061560826241"}},{"msg_index":33,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"141009000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"141009000"},"demand_coin_denom":"denomY","order_price":"0.027726799991752025"}},{"msg_index":34,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"98279000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"98279000"},"demand_coin_denom":"denomY","order_price":"0.027478993437704589"}},{"msg_index":35,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"76914000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf58c6rp0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"76914000"},"demand_coin_denom":"denomY","order_price":"0.027423925314582936"}},{"msg_index":36,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"23501500"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf46wwkua","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"23501500"},"demand_coin_denom":"denomY","order_price":"0.027754334053312851"}},{"msg_index":37,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4733282800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4733282800"},"demand_coin_denom":"denomX","order_price":"0.027699265930191198"}},{"msg_index":38,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3957334800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3957334800"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":39,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2483033600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2483033600"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":40,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5509230800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5509230800"},"demand_coin_denom":"denomX","order_price":"0.027561595622387067"}},{"msg_index":41,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2327844000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2327844000"},"demand_coin_denom":"denomX","order_price":"0.027423925314582936"}},{"msg_index":42,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4733282800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4733282800"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":43,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7061126800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7061126800"},"demand_coin_denom":"denomX","order_price":"0.027726799991752025"}},{"msg_index":44,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4655688000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4655688000"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":45,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3026197200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3026197200"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":46,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7293911200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7293911200"},"demand_coin_denom":"denomX","order_price":"0.027616663745508720"}},{"msg_index":47,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4810877600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4810877600"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":48,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4345308800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4345308800"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":49,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5509230800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5509230800"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":50,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4190119200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4190119200"},"demand_coin_denom":"denomX","order_price":"0.027451459376143762"}},{"msg_index":51,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"543163600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"543163600"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":52,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4578093200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4578093200"},"demand_coin_denom":"denomX","order_price":"0.027506527499265415"}},{"msg_index":53,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6517963200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6517963200"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":54,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"4190119200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"4190119200"},"demand_coin_denom":"denomX","order_price":"0.027368857191461284"}},{"msg_index":55,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1939870000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1939870000"},"demand_coin_denom":"denomX","order_price":"0.027754334053312851"}},{"msg_index":56,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1163922000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1163922000"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":57,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5897204800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5897204800"},"demand_coin_denom":"denomX","order_price":"0.027644197807069546"}},{"msg_index":58,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"155189600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"155189600"},"demand_coin_denom":"denomX","order_price":"0.027671731868630372"}},{"msg_index":59,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2250249200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2250249200"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":60,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2948602400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2948602400"},"demand_coin_denom":"denomX","order_price":"0.027286255006778805"}},{"msg_index":61,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7449100800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7449100800"},"demand_coin_denom":"denomX","order_price":"0.027313789068339631"}},{"msg_index":62,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6129989200"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6129989200"},"demand_coin_denom":"denomX","order_price":"0.027341323129900457"}},{"msg_index":63,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3491766000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3491766000"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":64,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6362773600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6362773600"},"demand_coin_denom":"denomX","order_price":"0.027726799991752025"}},{"msg_index":65,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"7138721600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"7138721600"},"demand_coin_denom":"denomX","order_price":"0.027534061560826241"}},{"msg_index":66,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3724550400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3724550400"},"demand_coin_denom":"denomX","order_price":"0.027616663745508720"}},{"msg_index":67,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3103792000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3103792000"},"demand_coin_denom":"denomX","order_price":"0.027589129683947893"}},{"msg_index":68,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"232784400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"232784400"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":69,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"6052394400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"6052394400"},"demand_coin_denom":"denomX","order_price":"0.027478993437704589"}},{"msg_index":70,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"5121256800"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"5121256800"},"demand_coin_denom":"denomX","order_price":"0.027644197807069546"}}]` - json.Unmarshal([]byte(swapMsgsJSON), &swapMsgs) + _ = json.Unmarshal([]byte(swapMsgsJSON), &swapMsgs) orderMap, xToY, yToX := types.MakeOrderMap(swapMsgs, DenomX, DenomY, onlyNotMatched) require.NotZero(t, len(orderMap)) require.NotNil(t, xToY) From 2e6730827be378cb9b6e4cac92a121fb2c557d57 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Tue, 25 Apr 2023 12:47:44 +0700 Subject: [PATCH 09/24] fix redefinition of builtin types --- app/test_helpers.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/test_helpers.go b/app/test_helpers.go index 7e9d3da2f8c..a320d9954b9 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -340,8 +340,8 @@ func TestDepositPool(t *testing.T, simapp *GaiaApp, ctx sdk.Context, x, y sdk.In require.Equal(t, moduleAccEscrowAmtX, moduleAccEscrowAmtXAfter) require.Equal(t, moduleAccEscrowAmtY, moduleAccEscrowAmtYAfter) } - batch, bool := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) - require.True(t, bool) + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) // endblock if withEndblock { @@ -401,8 +401,8 @@ func TestWithdrawPool(t *testing.T, simapp *GaiaApp, ctx sdk.Context, poolCoinAm // endblock liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) - batch, bool := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) - require.True(t, bool) + batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) + require.True(t, found) // verify burned pool coin poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) From 0905653408fa3ee4947be4999bef24f45520ba5f Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Tue, 25 Apr 2023 12:49:41 +0700 Subject: [PATCH 10/24] convert if-else to switch --- x/liquidity/simulation/operations_test.go | 1 + x/liquidity/types/swap_test.go | 2 +- x/liquidity/types/utils.go | 7 ++++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/x/liquidity/simulation/operations_test.go b/x/liquidity/simulation/operations_test.go index 613848f1124..f7bb7234190 100644 --- a/x/liquidity/simulation/operations_test.go +++ b/x/liquidity/simulation/operations_test.go @@ -211,6 +211,7 @@ func getTestingAccounts(_ *testing.T, r *rand.Rand, app *lapp.GaiaApp, ctx sdk.C } func setupLiquidityPools(t *testing.T, r *rand.Rand, app *lapp.GaiaApp, ctx sdk.Context, accounts []simtypes.Account) { + t.Helper() params := app.StakingKeeper.GetParams(ctx) for _, account := range accounts { diff --git a/x/liquidity/types/swap_test.go b/x/liquidity/types/swap_test.go index 365058e8cae..22276884483 100644 --- a/x/liquidity/types/swap_test.go +++ b/x/liquidity/types/swap_test.go @@ -525,7 +525,7 @@ func TestCalculateNoMatchEdgeCase(t *testing.T) { require.NoError(t, err) var orderBook types.OrderBook orderbookEdgeCase := `[{"Price":"1.007768598527187219","BuyOfferAmt":"0","SellOfferAmt":"417269600","BatchPoolSwapMsgs":[{"msg_index":1,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"417269600"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"417269600"},"demand_coin_denom":"denomX","order_price":"1.007768598527187219"}}]},{"Price":"1.011799672921295968","BuyOfferAmt":"0","SellOfferAmt":"2190665400","BatchPoolSwapMsgs":[{"msg_index":2,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2190665400"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2190665400"},"demand_coin_denom":"denomX","order_price":"1.011799672921295968"}}]}]` - json.Unmarshal([]byte(orderbookEdgeCase), &orderBook) + _ = json.Unmarshal([]byte(orderbookEdgeCase), &orderBook) r := orderBook.CalculateMatchStay(currentPrice) require.Equal(t, types.NoMatch, r.MatchType) // stay case with fractional diff --git a/x/liquidity/types/utils.go b/x/liquidity/types/utils.go index d8e1fde0cb5..8f9a0e243e5 100644 --- a/x/liquidity/types/utils.go +++ b/x/liquidity/types/utils.go @@ -73,11 +73,12 @@ func GetCoinsTotalAmount(coins sdk.Coins) sdk.Int { // ValidateReserveCoinLimit checks if total amounts of depositCoins exceed maxReserveCoinAmount. func ValidateReserveCoinLimit(maxReserveCoinAmount sdk.Int, depositCoins sdk.Coins) error { totalAmount := GetCoinsTotalAmount(depositCoins) - if maxReserveCoinAmount.IsZero() { + switch { + case maxReserveCoinAmount.IsZero(): return nil - } else if totalAmount.GT(maxReserveCoinAmount) { + case totalAmount.GT(maxReserveCoinAmount): return ErrExceededReserveCoinLimit - } else { + default: return nil } } From a597fc5fb2df3b0bb66d301d8f2e7cdc208b489a Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Tue, 25 Apr 2023 12:52:57 +0700 Subject: [PATCH 11/24] fix if-else chains --- app/test_helpers.go | 14 ++++++++------ x/liquidity/types/swap.go | 16 +++++++++------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/app/test_helpers.go b/app/test_helpers.go index a320d9954b9..9ba4646afba 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -447,11 +447,12 @@ func TestSwapPool(t *testing.T, simapp *GaiaApp, ctx sdk.Context, offerCoins []s SaveAccountWithFee(simapp, ctx, addrs[i], sdk.NewCoins(offerCoins[i]), offerCoins[i]) } var demandCoinDenom string - if pool.ReserveCoinDenoms[0] == offerCoins[i].Denom { + switch offerCoins[i].Denom { + case pool.ReserveCoinDenoms[0]: demandCoinDenom = pool.ReserveCoinDenoms[1] - } else if pool.ReserveCoinDenoms[1] == offerCoins[i].Denom { + case pool.ReserveCoinDenoms[1]: demandCoinDenom = pool.ReserveCoinDenoms[0] - } else { + default: require.True(t, false) } @@ -497,11 +498,12 @@ func GetSwapMsg(t *testing.T, simapp *GaiaApp, ctx sdk.Context, offerCoins []sdk SaveAccountWithFee(simapp, ctx, addrs[i], sdk.NewCoins(offerCoins[i]), offerCoins[i]) } var demandCoinDenom string - if pool.ReserveCoinDenoms[0] == offerCoins[i].Denom { + switch offerCoins[i].Denom { + case pool.ReserveCoinDenoms[0]: demandCoinDenom = pool.ReserveCoinDenoms[1] - } else if pool.ReserveCoinDenoms[1] == offerCoins[i].Denom { + case pool.ReserveCoinDenoms[1]: demandCoinDenom = pool.ReserveCoinDenoms[0] - } else { + default: require.True(t, false) } diff --git a/x/liquidity/types/swap.go b/x/liquidity/types/swap.go index 423dfba1016..955de461901 100644 --- a/x/liquidity/types/swap.go +++ b/x/liquidity/types/swap.go @@ -187,12 +187,12 @@ func (orderBook OrderBook) CalculateMatchStay(currentPrice sdk.Dec) (r BatchResu r.PriceDirection = Staying s := r.SwapPrice.Mul(r.EY) - if r.EX.IsZero() || r.EY.IsZero() { + switch { + case r.EX.IsZero() || r.EY.IsZero(): r.MatchType = NoMatch - } else if r.EX.Equal(s) { // Normalization to an integrator for easy determination of exactMatch + case r.EX.Equal(s): r.MatchType = ExactMatch - } else { - // Decimal Error, When calculating the Executable value, conservatively Truncated decimal + default: r.MatchType = FractionalMatch if r.EX.GT(s) { r.EX = s @@ -200,6 +200,7 @@ func (orderBook OrderBook) CalculateMatchStay(currentPrice sdk.Dec) (r BatchResu r.EY = r.EX.Quo(r.SwapPrice) } } + return } @@ -318,12 +319,13 @@ func (orderBook OrderBook) PriceDirection(currentPrice sdk.Dec) PriceDirection { sellAmtAtCurrentPrice := sdk.ZeroDec() for _, order := range orderBook { - if order.Price.GT(currentPrice) { + switch { + case order.Price.GT(currentPrice): buyAmtOverCurrentPrice = buyAmtOverCurrentPrice.Add(order.BuyOfferAmt.ToDec()) - } else if order.Price.Equal(currentPrice) { + case order.Price.Equal(currentPrice): buyAmtAtCurrentPrice = buyAmtAtCurrentPrice.Add(order.BuyOfferAmt.ToDec()) sellAmtAtCurrentPrice = sellAmtAtCurrentPrice.Add(order.SellOfferAmt.ToDec()) - } else if order.Price.LT(currentPrice) { + case order.Price.LT(currentPrice): sellAmtUnderCurrentPrice = sellAmtUnderCurrentPrice.Add(order.SellOfferAmt.ToDec()) } } From 2f31077c00122107d7a338ed0144a6dcaadc127b Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Wed, 26 Apr 2023 02:21:37 +0700 Subject: [PATCH 12/24] resolve empty block and additional testing improvements --- app/test_helpers.go | 4 ++-- x/liquidity/handler_test.go | 4 ++-- x/liquidity/keeper/batch.go | 13 +++++------- x/liquidity/keeper/batch_test.go | 4 ++-- x/liquidity/keeper/common_test.go | 5 +++-- x/liquidity/keeper/liquidity_pool_test.go | 2 +- x/liquidity/keeper/querier_test.go | 6 ++++-- x/liquidity/keeper/store_test.go | 24 +++++++++++------------ x/liquidity/keeper/swap_test.go | 1 + x/liquidity/types/swap.go | 20 +++++++++---------- x/liquidity/types/swap_test.go | 2 +- 11 files changed, 43 insertions(+), 42 deletions(-) diff --git a/app/test_helpers.go b/app/test_helpers.go index 9ba4646afba..7db0b47a24b 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -388,8 +388,7 @@ func TestWithdrawPool(t *testing.T, simapp *GaiaApp, ctx sdk.Context, poolCoinAm require.Equal(t, moduleAccEscrowAmtPool, moduleAccEscrowAmtPoolAfter) balancePoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[i], pool.PoolCoinDenom) - if balancePoolCoin.Amount.Equal(withdrawCoin.Amount) { - } else { + if !balancePoolCoin.Amount.Equal(withdrawCoin.Amount) { require.Equal(t, balancePoolCoin.Sub(withdrawCoin).Amount, balancePoolCoinAfter.Amount) } @@ -481,6 +480,7 @@ func TestSwapPool(t *testing.T, simapp *GaiaApp, ctx sdk.Context, offerCoins []s func GetSwapMsg(t *testing.T, simapp *GaiaApp, ctx sdk.Context, offerCoins []sdk.Coin, orderPrices []sdk.Dec, addrs []sdk.AccAddress, poolID uint64, ) []*types.MsgSwapWithinBatch { + t.Helper() if len(offerCoins) != len(orderPrices) || len(orderPrices) != len(addrs) { require.True(t, false) } diff --git a/x/liquidity/handler_test.go b/x/liquidity/handler_test.go index eade4777cff..288171c9d40 100644 --- a/x/liquidity/handler_test.go +++ b/x/liquidity/handler_test.go @@ -32,8 +32,8 @@ func TestMsgServerCreatePool(t *testing.T) { poolTypeID := types.DefaultPoolTypeID addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) - denomA := "uETH" - denomB := "uUSD" + denomA := "uETH" //nolint:goconst // this is redefined so we won't use a constant + denomB := "uUSD" //nolint:goconst // this is redefined so we won't use a constant denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) diff --git a/x/liquidity/keeper/batch.go b/x/liquidity/keeper/batch.go index 3b5a0a031c0..bd79d9c29f6 100644 --- a/x/liquidity/keeper/batch.go +++ b/x/liquidity/keeper/batch.go @@ -140,18 +140,15 @@ func (k Keeper) ExecutePoolBatches(ctx sdk.Context) { // HoldEscrow sends coins to the module account for an escrow. func (k Keeper) HoldEscrow(ctx sdk.Context, depositor sdk.AccAddress, depositCoins sdk.Coins) error { - if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, depositor, types.ModuleName, depositCoins); err != nil { - return err - } - return nil + err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, depositor, types.ModuleName, depositCoins) + return err } // If batch messages have expired or have not been processed, coins that were deposited with this function are refunded to the escrow. func (k Keeper) ReleaseEscrow(ctx sdk.Context, withdrawer sdk.AccAddress, withdrawCoins sdk.Coins) error { - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, withdrawer, withdrawCoins); err != nil { - return err - } - return nil + err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, withdrawer, withdrawCoins) + + return err } // Generate inputs and outputs to treat escrow refunds atomically. diff --git a/x/liquidity/keeper/batch_test.go b/x/liquidity/keeper/batch_test.go index c5336087790..ae545cdde93 100644 --- a/x/liquidity/keeper/batch_test.go +++ b/x/liquidity/keeper/batch_test.go @@ -572,9 +572,9 @@ func TestLiquidityScenario(t *testing.T) { // create two pools with the different denomY of 1000X and 1000Y coins poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) - poolId2 := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, "testDenom", addrs[0]) + poolID2 := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, "testDenom", addrs[0]) require.Equal(t, uint64(1), poolID) - require.Equal(t, uint64(2), poolId2) + require.Equal(t, uint64(2), poolID2) app.TestDepositPool(t, simapp, ctx, X, Y, addrs[1:10], poolID, true) diff --git a/x/liquidity/keeper/common_test.go b/x/liquidity/keeper/common_test.go index e796207cd5c..512a7135dcb 100644 --- a/x/liquidity/keeper/common_test.go +++ b/x/liquidity/keeper/common_test.go @@ -20,6 +20,7 @@ func createLiquidity(t *testing.T, ctx sdk.Context, simapp *app.GaiaApp) ( []sdk.AccAddress, []types.Pool, []types.PoolBatch, []types.DepositMsgState, []types.WithdrawMsgState, ) { + t.Helper() simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) // define test denom X, Y for Liquidity Pool @@ -78,11 +79,11 @@ func createLiquidity(t *testing.T, ctx sdk.Context, simapp *app.GaiaApp) ( return addrs, pools, batches, depositMsgs, withdrawMsgs } -func createTestPool(X, Y sdk.Coin) (*app.GaiaApp, sdk.Context, types.Pool, sdk.AccAddress, error) { +func createTestPool(x, y sdk.Coin) (*app.GaiaApp, sdk.Context, types.Pool, sdk.AccAddress, error) { simapp, ctx := createTestInput() params := simapp.LiquidityKeeper.GetParams(ctx) - depositCoins := sdk.NewCoins(X, Y) + depositCoins := sdk.NewCoins(x, y) creatorAddr := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creatorAddr, types.DefaultPoolTypeID, depositCoins)) diff --git a/x/liquidity/keeper/liquidity_pool_test.go b/x/liquidity/keeper/liquidity_pool_test.go index 584054b5fa0..a5c61a4dddc 100644 --- a/x/liquidity/keeper/liquidity_pool_test.go +++ b/x/liquidity/keeper/liquidity_pool_test.go @@ -703,7 +703,7 @@ func TestReserveAccManipulation(t *testing.T) { require.Equal(t, reserveAccBalances, sdk.NewCoins(depositA, depositB)) // send coin to manipulate reserve account - simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA1)) + err = simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA1)) metadata := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pool) require.Equal(t, depositA.Add(manipulationReserveA1).Amount, metadata.ReserveCoins.AmountOf(denomA)) diff --git a/x/liquidity/keeper/querier_test.go b/x/liquidity/keeper/querier_test.go index 977da745be8..9dce63b68fe 100644 --- a/x/liquidity/keeper/querier_test.go +++ b/x/liquidity/keeper/querier_test.go @@ -19,6 +19,7 @@ import ( const custom = "custom" func getQueriedLiquidityPool(t *testing.T, ctx sdk.Context, cdc *codec.LegacyAmino, querier sdk.Querier, poolID uint64) (types.Pool, error) { + t.Helper() query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryLiquidityPool}, "/"), Data: cdc.MustMarshalJSON(types.QueryLiquidityPoolParams{PoolId: poolID}), @@ -34,6 +35,7 @@ func getQueriedLiquidityPool(t *testing.T, ctx sdk.Context, cdc *codec.LegacyAmi } func getQueriedLiquidityPools(t *testing.T, ctx sdk.Context, cdc *codec.LegacyAmino, querier sdk.Querier) (types.Pools, error) { + t.Helper() queryDelParams := types.NewQueryLiquidityPoolsParams(1, 100) bz, errRes := cdc.MarshalJSON(queryDelParams) fmt.Println(bz, errRes) @@ -100,9 +102,9 @@ func TestQueries(t *testing.T) { addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) - poolId2 := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, "testDenom", addrs[0]) + poolID2 := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, "testDenom", addrs[0]) require.Equal(t, uint64(1), poolID) - require.Equal(t, uint64(2), poolId2) + require.Equal(t, uint64(2), poolID2) // begin block, init app.TestDepositPool(t, simapp, ctx, X, Y, addrs[1:10], poolID, true) diff --git a/x/liquidity/keeper/store_test.go b/x/liquidity/keeper/store_test.go index cd0e7603804..e2b4b6dabbe 100644 --- a/x/liquidity/keeper/store_test.go +++ b/x/liquidity/keeper/store_test.go @@ -21,8 +21,8 @@ func TestGetAllLiquidityPoolBatchSwapMsgs(t *testing.T) { params := simapp.LiquidityKeeper.GetParams(ctx) // define test denom X, Y for Liquidity Pool - denomX := "denomX" - denomY := "denomY" + denomX := "denomX" //nolint:goconst // for testing + denomY := "denomY" //nolint:goconst // for testing denomX, denomY = types.AlphabeticalDenomPair(denomX, denomY) // get random X, Y amount for create pool @@ -169,7 +169,7 @@ func TestIterateAllBatchMsgs(t *testing.T) { addrs := app.AddTestAddrsIncremental(simapp, ctx, 20, sdk.NewInt(10000)) poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0]) - poolId2 := app.TestCreatePool(t, simapp, ctx, A, B, denomA, denomB, addrs[4]) + poolID2 := app.TestCreatePool(t, simapp, ctx, A, B, denomA, denomB, addrs[4]) batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID) require.True(t, found) @@ -196,17 +196,17 @@ func TestIterateAllBatchMsgs(t *testing.T) { ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) - app.TestDepositPool(t, simapp, ctx, A, B.QuoRaw(10), addrs[4:5], poolId2, false) - app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(1000), addrs[4:5], poolId2, false) - app.TestSwapPool(t, simapp, ctx, offerCoins2, xOrderPrices, addrs[4:5], poolId2, true) + app.TestDepositPool(t, simapp, ctx, A, B.QuoRaw(10), addrs[4:5], poolID2, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(1000), addrs[4:5], poolID2, false) + app.TestSwapPool(t, simapp, ctx, offerCoins2, xOrderPrices, addrs[4:5], poolID2, true) // next block ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) - app.TestDepositPool(t, simapp, ctx, A, B.QuoRaw(10), addrs[4:5], poolId2, false) - app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(1000), addrs[4:5], poolId2, false) - app.TestSwapPool(t, simapp, ctx, offerCoins2, xOrderPrices, addrs[4:5], poolId2, true) + app.TestDepositPool(t, simapp, ctx, A, B.QuoRaw(10), addrs[4:5], poolID2, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(1000), addrs[4:5], poolID2, false) + app.TestSwapPool(t, simapp, ctx, offerCoins2, xOrderPrices, addrs[4:5], poolID2, true) // next block, ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) @@ -250,8 +250,8 @@ func TestIterateAllBatchMsgs(t *testing.T) { require.Equal(t, 3, len(withdrawMsgsNotToDelete)) require.NotEqual(t, withdrawMsgsNotToDelete, withdrawMsgs) - app.TestDepositPool(t, simapp, ctx, A, B.QuoRaw(10), addrs[4:5], poolId2, false) - app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(1000), addrs[4:5], poolId2, false) + app.TestDepositPool(t, simapp, ctx, A, B.QuoRaw(10), addrs[4:5], poolID2, false) + app.TestWithdrawPool(t, simapp, ctx, sdk.NewInt(1000), addrs[4:5], poolID2, false) depositMsgs = simapp.LiquidityKeeper.GetAllDepositMsgStates(ctx) require.Equal(t, 5, len(depositMsgs)) @@ -302,7 +302,7 @@ func TestIterateAllBatchMsgs(t *testing.T) { app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) app.TestSwapPool(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID, false) app.TestSwapPool(t, simapp, ctx, yOfferCoins, yOrderPrices, yOrderAddrs, poolID, false) - app.TestSwapPool(t, simapp, ctx, offerCoins2, xOrderPrices, addrs[4:5], poolId2, false) + app.TestSwapPool(t, simapp, ctx, offerCoins2, xOrderPrices, addrs[4:5], poolID2, false) swapMsgsPool1 := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStates(ctx, batch) require.Equal(t, 4, len(swapMsgsPool1)) diff --git a/x/liquidity/keeper/swap_test.go b/x/liquidity/keeper/swap_test.go index b255fbcbf3a..2e2d8b534fe 100644 --- a/x/liquidity/keeper/swap_test.go +++ b/x/liquidity/keeper/swap_test.go @@ -139,6 +139,7 @@ func TestSwapExecution(t *testing.T) { } func testSwapEdgeCases(t *testing.T, r *rand.Rand, simapp *app.GaiaApp, ctx sdk.Context, x, y sdk.Int, depositBalance sdk.Coins, addrs []sdk.AccAddress) { + t.Helper() // simapp, ctx := createTestInput() simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) params := simapp.LiquidityKeeper.GetParams(ctx) diff --git a/x/liquidity/types/swap.go b/x/liquidity/types/swap.go index 955de461901..a5fb437cbbb 100644 --- a/x/liquidity/types/swap.go +++ b/x/liquidity/types/swap.go @@ -218,17 +218,17 @@ func (orderBook OrderBook) CalculateMatch(direction PriceDirection, x, y sdk.Dec if (direction == Increasing && order.Price.LT(currentPrice)) || (direction == Decreasing && order.Price.GT(currentPrice)) { continue - } else { - orderPrice := order.Price - r := orderBook.CalculateSwap(direction, x, y, orderPrice, lastOrderPrice) - // Check to see if it exceeds a value that can be a decimal error - if (direction == Increasing && r.PoolY.Sub(r.EX.Quo(r.SwapPrice)).GTE(sdk.OneDec())) || - (direction == Decreasing && r.PoolX.Sub(r.EY.Mul(r.SwapPrice)).GTE(sdk.OneDec())) { - continue - } - matchScenarios = append(matchScenarios, r) - lastOrderPrice = orderPrice } + orderPrice := order.Price + r := orderBook.CalculateSwap(direction, x, y, orderPrice, lastOrderPrice) + // Check to see if it exceeds a value that can be a decimal error + if (direction == Increasing && r.PoolY.Sub(r.EX.Quo(r.SwapPrice)).GTE(sdk.OneDec())) || + (direction == Decreasing && r.PoolX.Sub(r.EY.Mul(r.SwapPrice)).GTE(sdk.OneDec())) { + continue + } + matchScenarios = append(matchScenarios, r) + lastOrderPrice = orderPrice + } maxScenario = NewBatchResult() for _, s := range matchScenarios { diff --git a/x/liquidity/types/swap_test.go b/x/liquidity/types/swap_test.go index 22276884483..8c399323f43 100644 --- a/x/liquidity/types/swap_test.go +++ b/x/liquidity/types/swap_test.go @@ -513,7 +513,7 @@ func TestCalculateMatchStayEdgeCase(t *testing.T) { require.NoError(t, err) var orderBook types.OrderBook orderbookEdgeCase := `[{"Price":"1.827780824157854573","BuyOfferAmt":"12587364000","SellOfferAmt":"6200948000","BatchPoolSwapMsgs":[{"msg_index":12,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2097894000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2097894000"},"demand_coin_denom":"denomY","order_price":"1.827780824157854573"}},{"msg_index":16,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4669506000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4669506000"},"demand_coin_denom":"denomY","order_price":"1.827780824157854573"}},{"msg_index":23,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"609066000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"609066000"},"demand_coin_denom":"denomY","order_price":"1.827780824157854573"}},{"msg_index":39,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5210898000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfckxufsg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5210898000"},"demand_coin_denom":"denomY","order_price":"1.827780824157854573"}},{"msg_index":56,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1284220000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg44npvhm","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1284220000"},"demand_coin_denom":"denomX","order_price":"1.827780824157854573"}},{"msg_index":78,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1981368000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfhft040s","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1981368000"},"demand_coin_denom":"denomX","order_price":"1.827780824157854573"}},{"msg_index":85,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2935360000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2yrhrufk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2935360000"},"demand_coin_denom":"denomX","order_price":"1.827780824157854573"}}]},{"Price":"1.829625204404229805","BuyOfferAmt":"9203664000","SellOfferAmt":"6971480000","BatchPoolSwapMsgs":[{"msg_index":18,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5210898000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5210898000"},"demand_coin_denom":"denomY","order_price":"1.829625204404229805"}},{"msg_index":36,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3992766000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf46wwkua","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3992766000"},"demand_coin_denom":"denomY","order_price":"1.829625204404229805"}},{"msg_index":44,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3155512000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3155512000"},"demand_coin_denom":"denomX","order_price":"1.829625204404229805"}},{"msg_index":55,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"513688000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"513688000"},"demand_coin_denom":"denomX","order_price":"1.829625204404229805"}},{"msg_index":61,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3302280000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3302280000"},"demand_coin_denom":"denomX","order_price":"1.829625204404229805"}}]},{"Price":"1.831469584650605036","BuyOfferAmt":"18001284000","SellOfferAmt":"2311596000","BatchPoolSwapMsgs":[{"msg_index":21,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3248352000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfqansamx","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3248352000"},"demand_coin_denom":"denomY","order_price":"1.831469584650605036"}},{"msg_index":32,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5007876000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5007876000"},"demand_coin_denom":"denomY","order_price":"1.831469584650605036"}},{"msg_index":33,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5955312000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5955312000"},"demand_coin_denom":"denomY","order_price":"1.831469584650605036"}},{"msg_index":34,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3789744000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3789744000"},"demand_coin_denom":"denomY","order_price":"1.831469584650605036"}},{"msg_index":65,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2311596000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2311596000"},"demand_coin_denom":"denomX","order_price":"1.831469584650605036"}}]},{"Price":"1.833313964896980268","BuyOfferAmt":"12113646000","SellOfferAmt":"4806652000","BatchPoolSwapMsgs":[{"msg_index":6,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6632052000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6632052000"},"demand_coin_denom":"denomY","order_price":"1.833313964896980268"}},{"msg_index":28,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5481594000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5481594000"},"demand_coin_denom":"denomY","order_price":"1.833313964896980268"}},{"msg_index":41,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"660456000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"660456000"},"demand_coin_denom":"denomX","order_price":"1.833313964896980268"}},{"msg_index":64,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2421672000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2421672000"},"demand_coin_denom":"denomX","order_price":"1.833313964896980268"}},{"msg_index":73,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1724524000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfjmhexac","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1724524000"},"demand_coin_denom":"denomX","order_price":"1.833313964896980268"}}]},{"Price":"1.835158345143355500","BuyOfferAmt":"0","SellOfferAmt":"6421100000","BatchPoolSwapMsgs":[{"msg_index":47,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2715208000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2715208000"},"demand_coin_denom":"denomX","order_price":"1.835158345143355500"}},{"msg_index":58,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2678516000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cghxkq0yk","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2678516000"},"demand_coin_denom":"denomX","order_price":"1.835158345143355500"}},{"msg_index":82,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1027376000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2p3t40m7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1027376000"},"demand_coin_denom":"denomX","order_price":"1.835158345143355500"}}]},{"Price":"1.837002725389730731","BuyOfferAmt":"9135990000","SellOfferAmt":"3852660000","BatchPoolSwapMsgs":[{"msg_index":13,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"744414000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"744414000"},"demand_coin_denom":"denomY","order_price":"1.837002725389730731"}},{"msg_index":19,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5143224000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5143224000"},"demand_coin_denom":"denomY","order_price":"1.837002725389730731"}},{"msg_index":22,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"541392000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"541392000"},"demand_coin_denom":"denomY","order_price":"1.837002725389730731"}},{"msg_index":35,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2706960000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf58c6rp0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2706960000"},"demand_coin_denom":"denomY","order_price":"1.837002725389730731"}},{"msg_index":48,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2274904000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2274904000"},"demand_coin_denom":"denomX","order_price":"1.837002725389730731"}},{"msg_index":51,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1394296000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1394296000"},"demand_coin_denom":"denomX","order_price":"1.837002725389730731"}},{"msg_index":80,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"183460000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfetsgud6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"183460000"},"demand_coin_denom":"denomX","order_price":"1.837002725389730731"}}]},{"Price":"1.838847105636105963","BuyOfferAmt":"6226008000","SellOfferAmt":"2715208000","BatchPoolSwapMsgs":[{"msg_index":5,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6226008000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6226008000"},"demand_coin_denom":"denomY","order_price":"1.838847105636105963"}},{"msg_index":43,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2715208000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2715208000"},"demand_coin_denom":"denomX","order_price":"1.838847105636105963"}}]},{"Price":"1.840691485882481195","BuyOfferAmt":"6496704000","SellOfferAmt":"3155512000","BatchPoolSwapMsgs":[{"msg_index":8,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6496704000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg8nhgh39","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6496704000"},"demand_coin_denom":"denomY","order_price":"1.840691485882481195"}},{"msg_index":81,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3155512000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2qvap6xv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3155512000"},"demand_coin_denom":"denomX","order_price":"1.840691485882481195"}}]},{"Price":"1.842535866128856426","BuyOfferAmt":"0","SellOfferAmt":"1137452000","BatchPoolSwapMsgs":[{"msg_index":45,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1137452000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgyayapl6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1137452000"},"demand_coin_denom":"denomX","order_price":"1.842535866128856426"}}]},{"Price":"1.844380246375231658","BuyOfferAmt":"15700368000","SellOfferAmt":"2274904000","BatchPoolSwapMsgs":[{"msg_index":14,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"1759524000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"1759524000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":24,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"1624176000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfrnq9t4e","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"1624176000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":25,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3248352000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfyjejm5u","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3248352000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":29,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4263462000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4263462000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":31,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4804854000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4804854000"},"demand_coin_denom":"denomY","order_price":"1.844380246375231658"}},{"msg_index":59,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1651140000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgcemnnmw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1651140000"},"demand_coin_denom":"denomX","order_price":"1.844380246375231658"}},{"msg_index":62,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"623764000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfpq9ygx5","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"623764000"},"demand_coin_denom":"denomX","order_price":"1.844380246375231658"}}]},{"Price":"1.846224626621606890","BuyOfferAmt":"19963830000","SellOfferAmt":"3338972000","BatchPoolSwapMsgs":[{"msg_index":11,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6429030000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgs80hl9n","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6429030000"},"demand_coin_denom":"denomY","order_price":"1.846224626621606890"}},{"msg_index":20,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5143224000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5143224000"},"demand_coin_denom":"denomY","order_price":"1.846224626621606890"}},{"msg_index":27,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2300916000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2300916000"},"demand_coin_denom":"denomY","order_price":"1.846224626621606890"}},{"msg_index":38,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6090660000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfhft040s","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6090660000"},"demand_coin_denom":"denomY","order_price":"1.846224626621606890"}},{"msg_index":42,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"660456000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"660456000"},"demand_coin_denom":"denomX","order_price":"1.846224626621606890"}},{"msg_index":68,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2678516000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf8u28d6r","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2678516000"},"demand_coin_denom":"denomX","order_price":"1.846224626621606890"}}]},{"Price":"1.848069006867982121","BuyOfferAmt":"0","SellOfferAmt":"3302280000","BatchPoolSwapMsgs":[{"msg_index":46,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2201520000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg9qjf5zg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2201520000"},"demand_coin_denom":"denomX","order_price":"1.848069006867982121"}},{"msg_index":70,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1100760000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1100760000"},"demand_coin_denom":"denomX","order_price":"1.848069006867982121"}}]},{"Price":"1.849913387114357353","BuyOfferAmt":"2233242000","SellOfferAmt":"10420528000","BatchPoolSwapMsgs":[{"msg_index":4,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2233242000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgrua237l","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2233242000"},"demand_coin_denom":"denomY","order_price":"1.849913387114357353"}},{"msg_index":54,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"917300000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgnfuzftv","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"917300000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":60,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3485740000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgeyd8xxu","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3485740000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":63,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"697148000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfzwk37gt","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"697148000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":66,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2421672000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2421672000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":84,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1357604000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2rzw5vgn","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1357604000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}},{"msg_index":87,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1541064000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2xsjzl6m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1541064000"},"demand_coin_denom":"denomX","order_price":"1.849913387114357353"}}]},{"Price":"1.851757767360732585","BuyOfferAmt":"23550552000","SellOfferAmt":"1577756000","BatchPoolSwapMsgs":[{"msg_index":1,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5075550000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgqjwl8sq","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5075550000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":7,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4128114000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgxwpuzvh","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4128114000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":9,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4940202000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4940202000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":15,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3113004000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg5g94e2f","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3113004000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":26,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"6293682000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf900xwfw","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"6293682000"},"demand_coin_denom":"denomY","order_price":"1.851757767360732585"}},{"msg_index":67,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"146768000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfxpunc83","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"146768000"},"demand_coin_denom":"denomX","order_price":"1.851757767360732585"}},{"msg_index":71,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1430988000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfsgjc9w4","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1430988000"},"demand_coin_denom":"denomX","order_price":"1.851757767360732585"}}]},{"Price":"1.853602147607107816","BuyOfferAmt":"3519048000","SellOfferAmt":"5577184000","BatchPoolSwapMsgs":[{"msg_index":10,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3519048000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3519048000"},"demand_coin_denom":"denomY","order_price":"1.853602147607107816"}},{"msg_index":52,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"403612000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cg36er2cp","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"403612000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":53,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"770532000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgj52kuk7","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"770532000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":72,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"146768000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf34yvsn8","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"146768000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":74,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3155512000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfnxpdnq2","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3155512000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":75,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"183460000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf58c6rp0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"183460000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}},{"msg_index":76,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"917300000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cf46wwkua","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"917300000"},"demand_coin_denom":"denomX","order_price":"1.853602147607107816"}}]},{"Price":"1.855446527853483048","BuyOfferAmt":"5752290000","SellOfferAmt":"1357604000","BatchPoolSwapMsgs":[{"msg_index":3,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"3654396000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgzpt7yrd","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"3654396000"},"demand_coin_denom":"denomY","order_price":"1.855446527853483048"}},{"msg_index":17,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2097894000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2097894000"},"demand_coin_denom":"denomY","order_price":"1.855446527853483048"}},{"msg_index":49,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1357604000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cggv6mtwa","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1357604000"},"demand_coin_denom":"denomX","order_price":"1.855446527853483048"}}]},{"Price":"1.857290908099858280","BuyOfferAmt":"2774634000","SellOfferAmt":"4256272000","BatchPoolSwapMsgs":[{"msg_index":37,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"2774634000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfk5amqjz","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"2774634000"},"demand_coin_denom":"denomY","order_price":"1.857290908099858280"}},{"msg_index":50,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"2128136000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgf3v07n0","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"2128136000"},"demand_coin_denom":"denomX","order_price":"1.857290908099858280"}},{"msg_index":77,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"256844000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfk5amqjz","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"256844000"},"demand_coin_denom":"denomX","order_price":"1.857290908099858280"}},{"msg_index":83,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1871292000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c2zlcqe4p","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1871292000"},"demand_coin_denom":"denomX","order_price":"1.857290908099858280"}}]},{"Price":"1.859135288346233511","BuyOfferAmt":"10760166000","SellOfferAmt":"5283648000","BatchPoolSwapMsgs":[{"msg_index":2,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"1421154000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgp0ctjdj","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"1421154000"},"demand_coin_denom":"denomY","order_price":"1.859135288346233511"}},{"msg_index":30,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"4331136000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cff73qycf","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"4331136000"},"demand_coin_denom":"denomY","order_price":"1.859135288346233511"}},{"msg_index":40,"executed":true,"exchanged_offer_coin":{"denom":"denomX","amount":"0"},"remaining_offer_coin":{"denom":"denomX","amount":"5007876000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfetsgud6","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomX","amount":"5007876000"},"demand_coin_denom":"denomY","order_price":"1.859135288346233511"}},{"msg_index":57,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"1137452000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cgkmq56ey","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"1137452000"},"demand_coin_denom":"denomX","order_price":"1.859135288346233511"}},{"msg_index":69,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"293536000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfgr8539m","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"293536000"},"demand_coin_denom":"denomX","order_price":"1.859135288346233511"}},{"msg_index":79,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"3302280000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5cfckxufsg","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"3302280000"},"demand_coin_denom":"denomX","order_price":"1.859135288346233511"}},{"msg_index":86,"executed":true,"exchanged_offer_coin":{"denom":"denomY","amount":"0"},"remaining_offer_coin":{"denom":"denomY","amount":"550380000"},"msg":{"swap_requester_address":"cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5c297phf5y","pool_id":1,"pool_type_id":1,"offer_coin":{"denom":"denomY","amount":"550380000"},"demand_coin_denom":"denomX","order_price":"1.859135288346233511"}}]}]` - json.Unmarshal([]byte(orderbookEdgeCase), &orderBook) + _ = json.Unmarshal([]byte(orderbookEdgeCase), &orderBook) r := orderBook.CalculateMatchStay(currentPrice) require.Equal(t, types.FractionalMatch, r.MatchType) // stay case with fractional From 13d82df676331d07ad5153d8ec170529da6bdfec Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Wed, 26 Apr 2023 03:31:46 +0700 Subject: [PATCH 13/24] fix protos --- Makefile | 18 +++--------- x/globalfee/types/query.pb.gw.go | 36 ++++++++++++----------- x/liquidity/keeper/liquidity_pool_test.go | 11 +++---- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/Makefile b/Makefile index a09ec6ea85e..09748e5908a 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ BUILDDIR ?= $(CURDIR)/build TEST_DOCKER_REPO=cosmos/contrib-gaiatest GO_SYSTEM_VERSION = $(shell go version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1-2) -REQUIRE_GO_VERSION = 1.20 +REQUIRE_GO_VERSION = 1.18 export GO111MODULE = on @@ -97,7 +97,7 @@ include contrib/devtools/Makefile check_version: ifneq ($(GO_SYSTEM_VERSION), $(REQUIRE_GO_VERSION)) - @echo "ERROR: Go version 1.20 is required for $(VERSION) of Gaia." + @echo "ERROR: Go version 1.18 is required for $(VERSION) of Gaia." exit 1 endif @@ -218,24 +218,14 @@ docker-build-all: docker-build-debug docker-build-hermes ############################################################################### ### Linting ### ############################################################################### -golangci_lint_cmd=golangci-lint -golangci_version=v1.52.2 lint: @echo "--> Running linter" - @go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version) - @$(golangci_lint_cmd) run --timeout=10m - -lint-fix: - @echo "--> Running linter" - @go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version) - @$(golangci_lint_cmd) run --fix --out-format=tab --issues-exit-code=0 + @go run github.com/golangci/golangci-lint/cmd/golangci-lint run --timeout=10m format: - @go install mvdan.cc/gofumpt@latest - @go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version) find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/docs/statik/statik.go" -not -path "./tests/mocks/*" -not -name "*.pb.go" -not -name "*.pb.gw.go" -not -name "*.pulsar.go" -not -path "./crypto/keys/secp256k1/*" | xargs gofumpt -w -l - $(golangci_lint_cmd) run --fix + golangci-lint run --fix .PHONY: format ############################################################################### diff --git a/x/globalfee/types/query.pb.gw.go b/x/globalfee/types/query.pb.gw.go index 0e33d9df1a5..b1efbc67d7d 100644 --- a/x/globalfee/types/query.pb.gw.go +++ b/x/globalfee/types/query.pb.gw.go @@ -13,15 +13,14 @@ import ( "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" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/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" + "google.golang.org/protobuf/proto" ) // Suppress "imported and not used" errors @@ -30,7 +29,6 @@ var _ io.Reader var _ status.Status var _ = runtime.String var _ = utilities.NewDoubleArray -var _ = descriptor.ForMessage var _ = metadata.Join func request_Query_MinimumGasPrices_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -63,20 +61,22 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/gaia.globalfee.v1beta1.Query/MinimumGasPrices", runtime.WithHTTPPathPattern("/gaia/globalfee/v1beta1/minimum_gas_prices")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_MinimumGasPrices_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_MinimumGasPrices_0(annotatedContext, 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) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Query_MinimumGasPrices_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_MinimumGasPrices_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -86,7 +86,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv // 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...) + conn, err := grpc.DialContext(ctx, endpoint, opts...) if err != nil { return err } @@ -125,19 +125,21 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/gaia.globalfee.v1beta1.Query/MinimumGasPrices", runtime.WithHTTPPathPattern("/gaia/globalfee/v1beta1/minimum_gas_prices")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_MinimumGasPrices_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) + resp, md, err := request_Query_MinimumGasPrices_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Query_MinimumGasPrices_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_MinimumGasPrices_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -145,7 +147,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_MinimumGasPrices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"gaia", "globalfee", "v1beta1", "minimum_gas_prices"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_MinimumGasPrices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"gaia", "globalfee", "v1beta1", "minimum_gas_prices"}, "")) ) var ( diff --git a/x/liquidity/keeper/liquidity_pool_test.go b/x/liquidity/keeper/liquidity_pool_test.go index a5c61a4dddc..4fdf4161bc1 100644 --- a/x/liquidity/keeper/liquidity_pool_test.go +++ b/x/liquidity/keeper/liquidity_pool_test.go @@ -39,7 +39,7 @@ func TestCreatePool(t *testing.T) { poolTypeID := types.DefaultPoolTypeID addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) - denomA := "uETH" + denomA := "uETH" //nolint denomB := "uUSD" denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) @@ -704,13 +704,14 @@ func TestReserveAccManipulation(t *testing.T) { // send coin to manipulate reserve account err = simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA1)) + require.NoError(t, err) metadata := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pool) require.Equal(t, depositA.Add(manipulationReserveA1).Amount, metadata.ReserveCoins.AmountOf(denomA)) _ = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, withdrawerPoolCoinBefore.Amount.QuoRaw(2))) - simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + _, _ = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) poolBatch, _ := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) _ = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) @@ -718,8 +719,8 @@ func TestReserveAccManipulation(t *testing.T) { liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) // send coin to manipulate reserve account - simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA2)) - simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveOther)) + _ = simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA2)) + _ = simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveOther)) _ = simapp.BankKeeper.GetAllBalances(ctx, reserveAcc) metadata = simapp.LiquidityKeeper.GetPoolMetaData(ctx, pool) require.NotEqual(t, manipulationReserveOther, metadata.ReserveCoins.AmountOf(sdk.DefaultBondDenom)) @@ -729,7 +730,7 @@ func TestReserveAccManipulation(t *testing.T) { withdrawerPoolCoinBefore = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) withdrawMsg = types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) - _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) + _, _ = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) require.NoError(t, err) poolBatch, _ = simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) From 2bbf3f395f93b6276687ed702fe48ec3b77a4b93 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Fri, 28 Apr 2023 10:26:27 +0700 Subject: [PATCH 14/24] update proto builder to v9 --- Makefile | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 09748e5908a..103f2c2dab3 100644 --- a/Makefile +++ b/Makefile @@ -263,20 +263,35 @@ test-docker-push: test-docker .PHONY: all build-linux install format lint go-mod-cache draw-deps clean build \ docker-build-debug docker-build-hermes docker-build-all - ############################################################################### ### Protobuf ### ############################################################################### + +containerProtoVer=0.9.0 +containerProtoImage=ghcr.io/cosmos/proto-builder:$(containerProtoVer) +containerProtoGen=cosmos-sdk-proto-gen-$(containerProtoVer) +containerProtoGenSwagger=cosmos-sdk-proto-gen-swagger-$(containerProtoVer) +containerProtoFmt=cosmos-sdk-proto-fmt-$(containerProtoVer) + +proto-all: proto-format proto-lint proto-gen + proto-gen: @echo "Generating Protobuf files" - @sh ./proto/scripts/protocgen.sh + @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGen}$$"; then docker start -a $(containerProtoGen); else docker run --name $(containerProtoGen) -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ + sh ./proto/scripts/protocgen.sh; fi -proto-doc: - @echo "Generating Protoc docs" - @sh ./proto/scripts/protoc-doc-gen.sh +proto-format: + @echo "Formatting Protobuf files" + @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoFmt}$$"; then docker start -a $(containerProtoFmt); else docker run --name $(containerProtoFmt) -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \ + find ./ -not -path "./third_party/*" -name "*.proto" -exec clang-format -i {} \; ; fi proto-swagger-gen: @echo "Generating Protobuf Swagger" - @sh ./proto/scripts/protoc-swagger-gen.sh + @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGenSwagger}$$"; then docker start -a $(containerProtoGenSwagger); else docker run --name $(containerProtoGenSwagger) -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ + sh ./proto/scripts/protoc-swagger-gen.sh; fi + +proto-lint: + @$(DOCKER_BUF) lint --error-format=json -.PHONY: proto-gen proto-doc proto-swagger-gen +proto-check-breaking: + @$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=main From 66d59a22bb76e94aa2dc05cf3a691d984f78e19c Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Wed, 3 May 2023 21:50:04 +0000 Subject: [PATCH 15/24] Merge remote-tracking branch 'origin/main' into botique-modules-go-in-x --- Makefile | 9 ++++++--- buf.work.yaml | 9 +++++++++ proto/buf.yaml | 20 +++++++++++++++++++ {proto/scripts => scripts}/protoc-doc-gen.sh | 0 .../scripts => scripts}/protoc-swagger-gen.sh | 0 {proto/scripts => scripts}/protocgen.sh | 0 6 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 buf.work.yaml create mode 100644 proto/buf.yaml rename {proto/scripts => scripts}/protoc-doc-gen.sh (100%) rename {proto/scripts => scripts}/protoc-swagger-gen.sh (100%) rename {proto/scripts => scripts}/protocgen.sh (100%) diff --git a/Makefile b/Makefile index 103f2c2dab3..1fc9851d8c5 100644 --- a/Makefile +++ b/Makefile @@ -263,12 +263,13 @@ test-docker-push: test-docker .PHONY: all build-linux install format lint go-mod-cache draw-deps clean build \ docker-build-debug docker-build-hermes docker-build-all + ############################################################################### ### Protobuf ### ############################################################################### -containerProtoVer=0.9.0 -containerProtoImage=ghcr.io/cosmos/proto-builder:$(containerProtoVer) +containerProtoVer=v0.2 +containerProtoImage=tendermintdev/sdk-proto-gen:$(containerProtoVer) containerProtoGen=cosmos-sdk-proto-gen-$(containerProtoVer) containerProtoGenSwagger=cosmos-sdk-proto-gen-swagger-$(containerProtoVer) containerProtoFmt=cosmos-sdk-proto-fmt-$(containerProtoVer) @@ -278,7 +279,9 @@ proto-all: proto-format proto-lint proto-gen proto-gen: @echo "Generating Protobuf files" @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGen}$$"; then docker start -a $(containerProtoGen); else docker run --name $(containerProtoGen) -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ - sh ./proto/scripts/protocgen.sh; fi + sh ./scripts/protocgen.sh; fi + + proto-format: @echo "Formatting Protobuf files" diff --git a/buf.work.yaml b/buf.work.yaml new file mode 100644 index 00000000000..98094695ffe --- /dev/null +++ b/buf.work.yaml @@ -0,0 +1,9 @@ +# Generated by "buf config migrate-v1beta1". Edit as necessary, and +# remove this comment when you're finished. +# +# This workspace file points to the roots found in your +# previous "buf.yaml" configuration. +version: v1 +directories: + - proto + - third_party/proto diff --git a/proto/buf.yaml b/proto/buf.yaml new file mode 100644 index 00000000000..aae636f0a14 --- /dev/null +++ b/proto/buf.yaml @@ -0,0 +1,20 @@ +# Generated by "buf config migrate-v1beta1". Edit as necessary, and +# remove this comment when you're finished. +# +# This module represents the "proto" root found in +# the previous configuration. +version: v1 +breaking: + use: + - FILE +lint: + use: + - DEFAULT + - COMMENTS + - FILE_LOWER_SNAKE_CASE + except: + - UNARY_RPC + - COMMENT_FIELD + - SERVICE_SUFFIX + - PACKAGE_VERSION_SUFFIX + - RPC_REQUEST_STANDARD_NAME diff --git a/proto/scripts/protoc-doc-gen.sh b/scripts/protoc-doc-gen.sh similarity index 100% rename from proto/scripts/protoc-doc-gen.sh rename to scripts/protoc-doc-gen.sh diff --git a/proto/scripts/protoc-swagger-gen.sh b/scripts/protoc-swagger-gen.sh similarity index 100% rename from proto/scripts/protoc-swagger-gen.sh rename to scripts/protoc-swagger-gen.sh diff --git a/proto/scripts/protocgen.sh b/scripts/protocgen.sh similarity index 100% rename from proto/scripts/protocgen.sh rename to scripts/protocgen.sh From f310dd5ffce0bb426ba0f167afc3368bd4ec398c Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Sat, 6 May 2023 13:34:20 +0700 Subject: [PATCH 16/24] Merge branch 'main' into use-ibc-proto-build --- .github/workflows/nightly-tests.yml | 48 +++++++++++++++++++++++++++-- x/globalfee/ante/fee.go | 9 ++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nightly-tests.yml b/.github/workflows/nightly-tests.yml index 0e92999313d..29bdbddca9e 100644 --- a/.github/workflows/nightly-tests.yml +++ b/.github/workflows/nightly-tests.yml @@ -6,11 +6,55 @@ on: - cron: "0 0 * * *" jobs: - run-tests: uses: cosmos/gaia/.github/workflows/test.yml@main run-simulations: uses: cosmos/gaia/.github/workflows/sims.yml@main - + run-vulncheck: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v3.5.2 + - uses: actions/setup-go@v4 + with: + go-version: 1.20.3 + - name: run-vulncheck + id: vulncheck + run: make vulncheck + + warn-if-failure: + if: failure() + needs: [run-tests, run-vulncheck, run-simulations] + runs-on: ubuntu-latest + steps: + - name: Notify Slack on failure + uses: slackapi/slack-github-action@v1.23.0 + env: + SLACK_WEBHOOK_URL: ${{ secrets.NIGHTLY_E2E_SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + BRANCH: ${{ github.ref_name }} + RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + COMMITS_URL: "${{ github.server_url }}/${{ github.repository }}/commits/${{ github.ref_name }}" + with: + payload: | + { + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "❗Nightly tests failed", + "emoji": true + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "See the <${{ env.RUN_URL }}|run details>" + } + } + ] + } diff --git a/x/globalfee/ante/fee.go b/x/globalfee/ante/fee.go index 909fac4a765..daec326aa77 100644 --- a/x/globalfee/ante/fee.go +++ b/x/globalfee/ante/fee.go @@ -73,6 +73,11 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne return ctx, err } + // reject the transaction early if the feeCoins have more denoms than the fee requirement + if feeCoins.Len() > requiredGlobalFees.Len() { + return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "fee is not a subset of required fees; got %s, required: %s", feeCoins.String(), requiredGlobalFees.String()) + } + // Get local minimum-gas-prices localFees := GetMinGasPrice(ctx, int64(feeTx.GetGas())) @@ -95,7 +100,7 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne // if feeCoinsNoZeroDenom=[], DenomsSubsetOf returns true // if feeCoinsNoZeroDenom is not empty, but nonZeroCoinFeesReq empty, return false if !feeCoinsNonZeroDenom.DenomsSubsetOf(nonZeroCoinFeesReq) { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "fee is not a subset of required fees; got %s, required: %s", feeCoins, combinedFeeRequirement) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "fee is not a subset of required fees; got %s, required: %s", feeCoins.String(), combinedFeeRequirement.String()) } // Accept zero fee transactions only if both of the following statements are true: @@ -132,7 +137,7 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne // because when nonZeroCoinFeesReq empty, and DenomsSubsetOf check passed, // the tx should already passed before) if !feeCoinsNonZeroDenom.IsAnyGTE(nonZeroCoinFeesReq) { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, combinedFeeRequirement) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins.String(), combinedFeeRequirement.String()) } } From 4bcdc8e89e4455af4e7528415f64d056d12b0197 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Sat, 6 May 2023 14:13:45 +0700 Subject: [PATCH 17/24] make proto build stuff match main --- Makefile | 2 -- buf.work.yaml | 2 +- third_party/proto/google/protobuf/any.proto | 3 ++ x/globalfee/types/query.pb.gw.go | 36 ++++++++++----------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 1fc9851d8c5..0b24ba4b310 100644 --- a/Makefile +++ b/Makefile @@ -281,8 +281,6 @@ proto-gen: @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGen}$$"; then docker start -a $(containerProtoGen); else docker run --name $(containerProtoGen) -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ sh ./scripts/protocgen.sh; fi - - proto-format: @echo "Formatting Protobuf files" @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoFmt}$$"; then docker start -a $(containerProtoFmt); else docker run --name $(containerProtoFmt) -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \ diff --git a/buf.work.yaml b/buf.work.yaml index 98094695ffe..8f730d02c3d 100644 --- a/buf.work.yaml +++ b/buf.work.yaml @@ -3,7 +3,7 @@ # # This workspace file points to the roots found in your # previous "buf.yaml" configuration. -version: v1 +version: v1beta1 directories: - proto - third_party/proto diff --git a/third_party/proto/google/protobuf/any.proto b/third_party/proto/google/protobuf/any.proto index 1431810ea45..58b511583a8 100644 --- a/third_party/proto/google/protobuf/any.proto +++ b/third_party/proto/google/protobuf/any.proto @@ -156,6 +156,9 @@ message Any { bytes value = 2; option (gogoproto.typedecl) = false; + option (gogoproto.goproto_stringer) = false; + option (gogoproto.gostring) = false; + option (gogoproto.stringer) = false; } option (gogoproto.goproto_registration) = false; diff --git a/x/globalfee/types/query.pb.gw.go b/x/globalfee/types/query.pb.gw.go index b1efbc67d7d..0e33d9df1a5 100644 --- a/x/globalfee/types/query.pb.gw.go +++ b/x/globalfee/types/query.pb.gw.go @@ -13,14 +13,15 @@ import ( "io" "net/http" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "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" - "google.golang.org/protobuf/proto" ) // Suppress "imported and not used" errors @@ -29,6 +30,7 @@ var _ io.Reader var _ status.Status var _ = runtime.String var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage var _ = metadata.Join func request_Query_MinimumGasPrices_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -61,22 +63,20 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/gaia.globalfee.v1beta1.Query/MinimumGasPrices", runtime.WithHTTPPathPattern("/gaia/globalfee/v1beta1/minimum_gas_prices")) + 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_MinimumGasPrices_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_MinimumGasPrices_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_MinimumGasPrices_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_MinimumGasPrices_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -86,7 +86,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv // 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.DialContext(ctx, endpoint, opts...) + conn, err := grpc.Dial(endpoint, opts...) if err != nil { return err } @@ -125,21 +125,19 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/gaia.globalfee.v1beta1.Query/MinimumGasPrices", runtime.WithHTTPPathPattern("/gaia/globalfee/v1beta1/minimum_gas_prices")) + rctx, err := runtime.AnnotateContext(ctx, mux, req) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_MinimumGasPrices_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + resp, md, err := request_Query_MinimumGasPrices_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_MinimumGasPrices_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_MinimumGasPrices_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -147,7 +145,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_MinimumGasPrices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"gaia", "globalfee", "v1beta1", "minimum_gas_prices"}, "")) + pattern_Query_MinimumGasPrices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"gaia", "globalfee", "v1beta1", "minimum_gas_prices"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( From 3848dbbe05638375a66cb3304146eb2d2faf0ae8 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Wed, 3 May 2023 21:50:04 +0000 Subject: [PATCH 18/24] build .proto files like most Cosmos projects --- Makefile | 4 ++++ buf.work.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0b24ba4b310..2d27823142f 100644 --- a/Makefile +++ b/Makefile @@ -264,6 +264,8 @@ test-docker-push: test-docker docker-build-debug docker-build-hermes docker-build-all + + ############################################################################### ### Protobuf ### ############################################################################### @@ -281,6 +283,8 @@ proto-gen: @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGen}$$"; then docker start -a $(containerProtoGen); else docker run --name $(containerProtoGen) -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ sh ./scripts/protocgen.sh; fi + + proto-format: @echo "Formatting Protobuf files" @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoFmt}$$"; then docker start -a $(containerProtoFmt); else docker run --name $(containerProtoFmt) -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \ diff --git a/buf.work.yaml b/buf.work.yaml index 8f730d02c3d..98094695ffe 100644 --- a/buf.work.yaml +++ b/buf.work.yaml @@ -3,7 +3,7 @@ # # This workspace file points to the roots found in your # previous "buf.yaml" configuration. -version: v1beta1 +version: v1 directories: - proto - third_party/proto From 77faa08845edd270b36eb91139b5397e0a878a6f Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Mon, 8 May 2023 13:36:27 +0700 Subject: [PATCH 19/24] add the liquidity module to the cosmos hub, reducing the scope for error --- Makefile | 34 +- go.mod | 1 + go.sum | 2 + proto/buf.gen.gogo.yaml | 8 + proto/buf.lock | 18 + proto/buf.yaml | 7 +- scripts/protocgen.sh | 26 +- third_party/proto/gogoproto/gogo.proto | 145 -------- .../proto/google/api/annotations.proto | 31 -- third_party/proto/google/api/http.proto | 318 ------------------ third_party/proto/google/api/httpbody.proto | 78 ----- x/globalfee/types/genesis.pb.go | 2 +- x/globalfee/types/query.pb.go | 2 +- x/globalfee/types/query.pb.gw.go | 2 +- 14 files changed, 61 insertions(+), 613 deletions(-) create mode 100644 proto/buf.gen.gogo.yaml create mode 100644 proto/buf.lock delete mode 100644 third_party/proto/gogoproto/gogo.proto delete mode 100644 third_party/proto/google/api/annotations.proto delete mode 100644 third_party/proto/google/api/http.proto delete mode 100644 third_party/proto/google/api/httpbody.proto diff --git a/Makefile b/Makefile index 2d27823142f..9977740384a 100644 --- a/Makefile +++ b/Makefile @@ -270,33 +270,31 @@ test-docker-push: test-docker ### Protobuf ### ############################################################################### -containerProtoVer=v0.2 -containerProtoImage=tendermintdev/sdk-proto-gen:$(containerProtoVer) -containerProtoGen=cosmos-sdk-proto-gen-$(containerProtoVer) -containerProtoGenSwagger=cosmos-sdk-proto-gen-swagger-$(containerProtoVer) -containerProtoFmt=cosmos-sdk-proto-fmt-$(containerProtoVer) +protoVer=0.9.0 +protoImageName=ghcr.io/cosmos/proto-builder:$(protoVer) +protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) proto-all: proto-format proto-lint proto-gen proto-gen: @echo "Generating Protobuf files" - @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGen}$$"; then docker start -a $(containerProtoGen); else docker run --name $(containerProtoGen) -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ - sh ./scripts/protocgen.sh; fi - - - -proto-format: - @echo "Formatting Protobuf files" - @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoFmt}$$"; then docker start -a $(containerProtoFmt); else docker run --name $(containerProtoFmt) -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \ - find ./ -not -path "./third_party/*" -name "*.proto" -exec clang-format -i {} \; ; fi + @$(protoImage) sh ./scripts/protocgen.sh proto-swagger-gen: @echo "Generating Protobuf Swagger" - @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGenSwagger}$$"; then docker start -a $(containerProtoGenSwagger); else docker run --name $(containerProtoGenSwagger) -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ - sh ./proto/scripts/protoc-swagger-gen.sh; fi + @$(protoImage) sh ./scripts/protoc-swagger-gen.sh + +proto-format: + @$(protoImage) find ./ -name "*.proto" -exec clang-format -i {} \; proto-lint: - @$(DOCKER_BUF) lint --error-format=json + @$(protoImage) buf lint --error-format=json proto-check-breaking: - @$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=main + @$(protoImage) buf breaking --against $(HTTPS_GIT)#branch=main + +proto-update-deps: + @echo "Updating Protobuf dependencies" + $(DOCKER) run --rm -v $(CURDIR)/proto:/workspace --workdir /workspace $(protoImageName) buf mod update + +.PHONY: proto-all proto-gen proto-gen-any proto-swagger-gen proto-format proto-lint proto-check-breaking proto-update-deps \ No newline at end of file diff --git a/go.mod b/go.mod index d3a1687dabb..c48af9f252b 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( cosmossdk.io/math v1.0.0 github.com/cosmos/cosmos-sdk v0.45.15 github.com/cosmos/go-bip39 v1.0.0 + github.com/cosmos/gogoproto v1.4.3 github.com/cosmos/ibc-go/v4 v4.3.0 github.com/cosmos/interchain-security v1.1.1 github.com/gogo/protobuf v1.3.3 diff --git a/go.sum b/go.sum index c857c3dfe0a..3d2acd32608 100644 --- a/go.sum +++ b/go.sum @@ -282,6 +282,8 @@ github.com/cosmos/cosmos-sdk v0.45.15-ics/go.mod h1:bScuNwWAP0TZJpUf+SHXRU3xGoUP github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= +github.com/cosmos/gogoproto v1.4.3 h1:RP3yyVREh9snv/lsOvmsAPQt8f44LgL281X0IOIhhcI= +github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU= github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cosmos/iavl v0.19.5 h1:rGA3hOrgNxgRM5wYcSCxgQBap7fW82WZgY78V9po/iY= diff --git a/proto/buf.gen.gogo.yaml b/proto/buf.gen.gogo.yaml new file mode 100644 index 00000000000..448aff1a268 --- /dev/null +++ b/proto/buf.gen.gogo.yaml @@ -0,0 +1,8 @@ +version: v1beta1 +plugins: + - name: gocosmos + out: .. + opt: plugins=grpc,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types + - name: grpc-gateway + out: .. + opt: logtostderr=true,allow_colon_final_segments=true diff --git a/proto/buf.lock b/proto/buf.lock new file mode 100644 index 00000000000..9d5c9237a75 --- /dev/null +++ b/proto/buf.lock @@ -0,0 +1,18 @@ +# Generated by buf. DO NOT EDIT. +version: v1 +deps: + - remote: buf.build + owner: cosmos + repository: cosmos-proto + commit: 1935555c206d4afb9e94615dfd0fad31 + digest: shake256:c74d91a3ac7ae07d579e90eee33abf9b29664047ac8816500cf22c081fec0d72d62c89ce0bebafc1f6fec7aa5315be72606717740ca95007248425102c365377 + - remote: buf.build + owner: cosmos + repository: gogo-proto + commit: 34d970b699f84aa382f3c29773a60836 + digest: shake256:3d3bee5229ba579e7d19ffe6e140986a228b48a8c7fe74348f308537ab95e9135210e81812489d42cd8941d33ff71f11583174ccc5972e86e6112924b6ce9f04 + - remote: buf.build + owner: googleapis + repository: googleapis + commit: cc916c31859748a68fd229a3c8d7a2e8 + digest: shake256:469b049d0eb04203d5272062636c078decefc96fec69739159c25d85349c50c34c7706918a8b216c5c27f76939df48452148cff8c5c3ae77fa6ba5c25c1b8bf8 diff --git a/proto/buf.yaml b/proto/buf.yaml index aae636f0a14..1fcdb3f996f 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -3,7 +3,12 @@ # # This module represents the "proto" root found in # the previous configuration. -version: v1 +version: v1beta1 +deps: + - buf.build/googleapis/googleapis + - buf.build/cosmos/cosmos-proto + - buf.build/cosmos/gogo-proto + breaking: use: - FILE diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index 14e901db6f7..3d0d54ec34f 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -2,29 +2,17 @@ set -eo pipefail -protoc_gen_gocosmos() { - if ! grep "github.com/gogo/protobuf => github.com/regen-network/protobuf" go.mod &>/dev/null ; then - echo -e "\tPlease run this command from somewhere inside the gaia folder." - return 1 - fi +echo "Generating gogo proto code" +cd proto - go get github.com/regen-network/cosmos-proto/protoc-gen-gocosmos@latest 2>/dev/null -} +buf generate --template buf.gen.gogo.yaml $file -protoc_gen_gocosmos +cd .. -proto_dirs=$(find ./proto -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) -for dir in $proto_dirs; do - protoc \ - -I "proto" \ - -I "third_party/proto" \ - --gocosmos_out=plugins=interfacetype+grpc,\ -Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types:. \ - --grpc-gateway_out=logtostderr=true:. \ - $(find "${dir}" -maxdepth 1 -name '*.proto') - -done # move proto files to the right places cp -r github.com/cosmos/gaia/x/* x/ rm -rf github.com + +go mod tidy + diff --git a/third_party/proto/gogoproto/gogo.proto b/third_party/proto/gogoproto/gogo.proto deleted file mode 100644 index 49e78f99fe5..00000000000 --- a/third_party/proto/gogoproto/gogo.proto +++ /dev/null @@ -1,145 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto2"; -package gogoproto; - -import "google/protobuf/descriptor.proto"; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "GoGoProtos"; -option go_package = "github.com/gogo/protobuf/gogoproto"; - -extend google.protobuf.EnumOptions { - optional bool goproto_enum_prefix = 62001; - optional bool goproto_enum_stringer = 62021; - optional bool enum_stringer = 62022; - optional string enum_customname = 62023; - optional bool enumdecl = 62024; -} - -extend google.protobuf.EnumValueOptions { - optional string enumvalue_customname = 66001; -} - -extend google.protobuf.FileOptions { - optional bool goproto_getters_all = 63001; - optional bool goproto_enum_prefix_all = 63002; - optional bool goproto_stringer_all = 63003; - optional bool verbose_equal_all = 63004; - optional bool face_all = 63005; - optional bool gostring_all = 63006; - optional bool populate_all = 63007; - optional bool stringer_all = 63008; - optional bool onlyone_all = 63009; - - optional bool equal_all = 63013; - optional bool description_all = 63014; - optional bool testgen_all = 63015; - optional bool benchgen_all = 63016; - optional bool marshaler_all = 63017; - optional bool unmarshaler_all = 63018; - optional bool stable_marshaler_all = 63019; - - optional bool sizer_all = 63020; - - optional bool goproto_enum_stringer_all = 63021; - optional bool enum_stringer_all = 63022; - - optional bool unsafe_marshaler_all = 63023; - optional bool unsafe_unmarshaler_all = 63024; - - optional bool goproto_extensions_map_all = 63025; - optional bool goproto_unrecognized_all = 63026; - optional bool gogoproto_import = 63027; - optional bool protosizer_all = 63028; - optional bool compare_all = 63029; - optional bool typedecl_all = 63030; - optional bool enumdecl_all = 63031; - - optional bool goproto_registration = 63032; - optional bool messagename_all = 63033; - - optional bool goproto_sizecache_all = 63034; - optional bool goproto_unkeyed_all = 63035; -} - -extend google.protobuf.MessageOptions { - optional bool goproto_getters = 64001; - optional bool goproto_stringer = 64003; - optional bool verbose_equal = 64004; - optional bool face = 64005; - optional bool gostring = 64006; - optional bool populate = 64007; - optional bool stringer = 67008; - optional bool onlyone = 64009; - - optional bool equal = 64013; - optional bool description = 64014; - optional bool testgen = 64015; - optional bool benchgen = 64016; - optional bool marshaler = 64017; - optional bool unmarshaler = 64018; - optional bool stable_marshaler = 64019; - - optional bool sizer = 64020; - - optional bool unsafe_marshaler = 64023; - optional bool unsafe_unmarshaler = 64024; - - optional bool goproto_extensions_map = 64025; - optional bool goproto_unrecognized = 64026; - - optional bool protosizer = 64028; - optional bool compare = 64029; - - optional bool typedecl = 64030; - - optional bool messagename = 64033; - - optional bool goproto_sizecache = 64034; - optional bool goproto_unkeyed = 64035; -} - -extend google.protobuf.FieldOptions { - optional bool nullable = 65001; - optional bool embed = 65002; - optional string customtype = 65003; - optional string customname = 65004; - optional string jsontag = 65005; - optional string moretags = 65006; - optional string casttype = 65007; - optional string castkey = 65008; - optional string castvalue = 65009; - - optional bool stdtime = 65010; - optional bool stdduration = 65011; - optional bool wktpointer = 65012; - - optional string castrepeated = 65013; -} diff --git a/third_party/proto/google/api/annotations.proto b/third_party/proto/google/api/annotations.proto deleted file mode 100644 index 85c361b47fe..00000000000 --- a/third_party/proto/google/api/annotations.proto +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2015, Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package google.api; - -import "google/api/http.proto"; -import "google/protobuf/descriptor.proto"; - -option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; -option java_multiple_files = true; -option java_outer_classname = "AnnotationsProto"; -option java_package = "com.google.api"; -option objc_class_prefix = "GAPI"; - -extend google.protobuf.MethodOptions { - // See `HttpRule`. - HttpRule http = 72295728; -} diff --git a/third_party/proto/google/api/http.proto b/third_party/proto/google/api/http.proto deleted file mode 100644 index 2bd3a19bfa5..00000000000 --- a/third_party/proto/google/api/http.proto +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package google.api; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; -option java_multiple_files = true; -option java_outer_classname = "HttpProto"; -option java_package = "com.google.api"; -option objc_class_prefix = "GAPI"; - - -// Defines the HTTP configuration for an API service. It contains a list of -// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method -// to one or more HTTP REST API methods. -message Http { - // A list of HTTP configuration rules that apply to individual API methods. - // - // **NOTE:** All service configuration rules follow "last one wins" order. - repeated HttpRule rules = 1; - - // When set to true, URL path parmeters will be fully URI-decoded except in - // cases of single segment matches in reserved expansion, where "%2F" will be - // left encoded. - // - // The default behavior is to not decode RFC 6570 reserved characters in multi - // segment matches. - bool fully_decode_reserved_expansion = 2; -} - -// `HttpRule` defines the mapping of an RPC method to one or more HTTP -// REST API methods. The mapping specifies how different portions of the RPC -// request message are mapped to URL path, URL query parameters, and -// HTTP request body. The mapping is typically specified as an -// `google.api.http` annotation on the RPC method, -// see "google/api/annotations.proto" for details. -// -// The mapping consists of a field specifying the path template and -// method kind. The path template can refer to fields in the request -// message, as in the example below which describes a REST GET -// operation on a resource collection of messages: -// -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; -// } -// } -// message GetMessageRequest { -// message SubMessage { -// string subfield = 1; -// } -// string message_id = 1; // mapped to the URL -// SubMessage sub = 2; // `sub.subfield` is url-mapped -// } -// message Message { -// string text = 1; // content of the resource -// } -// -// The same http annotation can alternatively be expressed inside the -// `GRPC API Configuration` YAML file. -// -// http: -// rules: -// - selector: .Messaging.GetMessage -// get: /v1/messages/{message_id}/{sub.subfield} -// -// This definition enables an automatic, bidrectional mapping of HTTP -// JSON to RPC. Example: -// -// HTTP | RPC -// -----|----- -// `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` -// -// In general, not only fields but also field paths can be referenced -// from a path pattern. Fields mapped to the path pattern cannot be -// repeated and must have a primitive (non-message) type. -// -// Any fields in the request message which are not bound by the path -// pattern automatically become (optional) HTTP query -// parameters. Assume the following definition of the request message: -// -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http).get = "/v1/messages/{message_id}"; -// } -// } -// message GetMessageRequest { -// message SubMessage { -// string subfield = 1; -// } -// string message_id = 1; // mapped to the URL -// int64 revision = 2; // becomes a parameter -// SubMessage sub = 3; // `sub.subfield` becomes a parameter -// } -// -// -// This enables a HTTP JSON to RPC mapping as below: -// -// HTTP | RPC -// -----|----- -// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` -// -// Note that fields which are mapped to HTTP parameters must have a -// primitive type or a repeated primitive type. Message types are not -// allowed. In the case of a repeated type, the parameter can be -// repeated in the URL, as in `...?param=A¶m=B`. -// -// For HTTP method kinds which allow a request body, the `body` field -// specifies the mapping. Consider a REST update method on the -// message resource collection: -// -// -// service Messaging { -// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { -// option (google.api.http) = { -// put: "/v1/messages/{message_id}" -// body: "message" -// }; -// } -// } -// message UpdateMessageRequest { -// string message_id = 1; // mapped to the URL -// Message message = 2; // mapped to the body -// } -// -// -// The following HTTP JSON to RPC mapping is enabled, where the -// representation of the JSON in the request body is determined by -// protos JSON encoding: -// -// HTTP | RPC -// -----|----- -// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` -// -// The special name `*` can be used in the body mapping to define that -// every field not bound by the path template should be mapped to the -// request body. This enables the following alternative definition of -// the update method: -// -// service Messaging { -// rpc UpdateMessage(Message) returns (Message) { -// option (google.api.http) = { -// put: "/v1/messages/{message_id}" -// body: "*" -// }; -// } -// } -// message Message { -// string message_id = 1; -// string text = 2; -// } -// -// -// The following HTTP JSON to RPC mapping is enabled: -// -// HTTP | RPC -// -----|----- -// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` -// -// Note that when using `*` in the body mapping, it is not possible to -// have HTTP parameters, as all fields not bound by the path end in -// the body. This makes this option more rarely used in practice of -// defining REST APIs. The common usage of `*` is in custom methods -// which don't use the URL at all for transferring data. -// -// It is possible to define multiple HTTP methods for one RPC by using -// the `additional_bindings` option. Example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/messages/{message_id}" -// additional_bindings { -// get: "/v1/users/{user_id}/messages/{message_id}" -// } -// }; -// } -// } -// message GetMessageRequest { -// string message_id = 1; -// string user_id = 2; -// } -// -// -// This enables the following two alternative HTTP JSON to RPC -// mappings: -// -// HTTP | RPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` -// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` -// -// # Rules for HTTP mapping -// -// The rules for mapping HTTP path, query parameters, and body fields -// to the request message are as follows: -// -// 1. The `body` field specifies either `*` or a field path, or is -// omitted. If omitted, it indicates there is no HTTP request body. -// 2. Leaf fields (recursive expansion of nested messages in the -// request) can be classified into three types: -// (a) Matched in the URL template. -// (b) Covered by body (if body is `*`, everything except (a) fields; -// else everything under the body field) -// (c) All other fields. -// 3. URL query parameters found in the HTTP request are mapped to (c) fields. -// 4. Any body sent with an HTTP request can contain only (b) fields. -// -// The syntax of the path template is as follows: -// -// Template = "/" Segments [ Verb ] ; -// Segments = Segment { "/" Segment } ; -// Segment = "*" | "**" | LITERAL | Variable ; -// Variable = "{" FieldPath [ "=" Segments ] "}" ; -// FieldPath = IDENT { "." IDENT } ; -// Verb = ":" LITERAL ; -// -// The syntax `*` matches a single path segment. The syntax `**` matches zero -// or more path segments, which must be the last part of the path except the -// `Verb`. The syntax `LITERAL` matches literal text in the path. -// -// The syntax `Variable` matches part of the URL path as specified by its -// template. A variable template must not contain other variables. If a variable -// matches a single path segment, its template may be omitted, e.g. `{var}` -// is equivalent to `{var=*}`. -// -// If a variable contains exactly one path segment, such as `"{var}"` or -// `"{var=*}"`, when such a variable is expanded into a URL path, all characters -// except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the -// Discovery Document as `{var}`. -// -// If a variable contains one or more path segments, such as `"{var=foo/*}"` -// or `"{var=**}"`, when such a variable is expanded into a URL path, all -// characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables -// show up in the Discovery Document as `{+var}`. -// -// NOTE: While the single segment variable matches the semantics of -// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 -// Simple String Expansion, the multi segment variable **does not** match -// RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion -// does not expand special characters like `?` and `#`, which would lead -// to invalid URLs. -// -// NOTE: the field paths in variables and in the `body` must not refer to -// repeated fields or map fields. -message HttpRule { - // Selects methods to which this rule applies. - // - // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. - string selector = 1; - - // Determines the URL pattern is matched by this rules. This pattern can be - // used with any of the {get|put|post|delete|patch} methods. A custom method - // can be defined using the 'custom' field. - oneof pattern { - // Used for listing and getting information about resources. - string get = 2; - - // Used for updating a resource. - string put = 3; - - // Used for creating a resource. - string post = 4; - - // Used for deleting a resource. - string delete = 5; - - // Used for updating a resource. - string patch = 6; - - // The custom pattern is used for specifying an HTTP method that is not - // included in the `pattern` field, such as HEAD, or "*" to leave the - // HTTP method unspecified for this rule. The wild-card rule is useful - // for services that provide content to Web (HTML) clients. - CustomHttpPattern custom = 8; - } - - // The name of the request field whose value is mapped to the HTTP body, or - // `*` for mapping all fields not captured by the path pattern to the HTTP - // body. NOTE: the referred field must not be a repeated field and must be - // present at the top-level of request message type. - string body = 7; - - // Optional. The name of the response field whose value is mapped to the HTTP - // body of response. Other response fields are ignored. When - // not set, the response message will be used as HTTP body of response. - string response_body = 12; - - // Additional HTTP bindings for the selector. Nested bindings must - // not contain an `additional_bindings` field themselves (that is, - // the nesting may only be one level deep). - repeated HttpRule additional_bindings = 11; -} - -// A custom pattern is used for defining custom HTTP verb. -message CustomHttpPattern { - // The name of this custom HTTP verb. - string kind = 1; - - // The path matched by this custom verb. - string path = 2; -} diff --git a/third_party/proto/google/api/httpbody.proto b/third_party/proto/google/api/httpbody.proto deleted file mode 100644 index 4428515c120..00000000000 --- a/third_party/proto/google/api/httpbody.proto +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -syntax = "proto3"; - -package google.api; - -import "google/protobuf/any.proto"; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody"; -option java_multiple_files = true; -option java_outer_classname = "HttpBodyProto"; -option java_package = "com.google.api"; -option objc_class_prefix = "GAPI"; - -// Message that represents an arbitrary HTTP body. It should only be used for -// payload formats that can't be represented as JSON, such as raw binary or -// an HTML page. -// -// -// This message can be used both in streaming and non-streaming API methods in -// the request as well as the response. -// -// It can be used as a top-level request field, which is convenient if one -// wants to extract parameters from either the URL or HTTP template into the -// request fields and also want access to the raw HTTP body. -// -// Example: -// -// message GetResourceRequest { -// // A unique request id. -// string request_id = 1; -// -// // The raw HTTP body is bound to this field. -// google.api.HttpBody http_body = 2; -// } -// -// service ResourceService { -// rpc GetResource(GetResourceRequest) returns (google.api.HttpBody); -// rpc UpdateResource(google.api.HttpBody) returns -// (google.protobuf.Empty); -// } -// -// Example with streaming methods: -// -// service CaldavService { -// rpc GetCalendar(stream google.api.HttpBody) -// returns (stream google.api.HttpBody); -// rpc UpdateCalendar(stream google.api.HttpBody) -// returns (stream google.api.HttpBody); -// } -// -// Use of this type only changes how the request and response bodies are -// handled, all other features will continue to work unchanged. -message HttpBody { - // The HTTP Content-Type header value specifying the content type of the body. - string content_type = 1; - - // The HTTP request/response body as raw binary. - bytes data = 2; - - // Application specific response metadata. Must be set in the first response - // for streaming APIs. - repeated google.protobuf.Any extensions = 3; -} \ No newline at end of file diff --git a/x/globalfee/types/genesis.pb.go b/x/globalfee/types/genesis.pb.go index bde069af626..914b77f1ed6 100644 --- a/x/globalfee/types/genesis.pb.go +++ b/x/globalfee/types/genesis.pb.go @@ -7,7 +7,7 @@ import ( fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" + _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" math "math" diff --git a/x/globalfee/types/query.pb.go b/x/globalfee/types/query.pb.go index 569b6975be4..94848fc4729 100644 --- a/x/globalfee/types/query.pb.go +++ b/x/globalfee/types/query.pb.go @@ -8,7 +8,7 @@ import ( fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/gogo/protobuf/gogoproto" + _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" _ "google.golang.org/genproto/googleapis/api/annotations" diff --git a/x/globalfee/types/query.pb.gw.go b/x/globalfee/types/query.pb.gw.go index 0e33d9df1a5..a7b2956f369 100644 --- a/x/globalfee/types/query.pb.gw.go +++ b/x/globalfee/types/query.pb.gw.go @@ -145,7 +145,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_MinimumGasPrices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"gaia", "globalfee", "v1beta1", "minimum_gas_prices"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_MinimumGasPrices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"gaia", "globalfee", "v1beta1", "minimum_gas_prices"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( From afb86c840f5a5ded4b525c5c994f5c9d53909b6b Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Mon, 8 May 2023 13:40:13 +0700 Subject: [PATCH 20/24] fix lint --- Makefile | 11 +++-------- x/liquidity/keeper/liquidity_pool_test.go | 4 ++-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 9977740384a..1ddb7884c0b 100644 --- a/Makefile +++ b/Makefile @@ -20,8 +20,7 @@ DOCKER := $(shell which docker) BUILDDIR ?= $(CURDIR)/build TEST_DOCKER_REPO=cosmos/contrib-gaiatest -GO_SYSTEM_VERSION = $(shell go version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1-2) -REQUIRE_GO_VERSION = 1.18 + export GO111MODULE = on @@ -95,11 +94,7 @@ include contrib/devtools/Makefile ### Build ### ############################################################################### -check_version: -ifneq ($(GO_SYSTEM_VERSION), $(REQUIRE_GO_VERSION)) - @echo "ERROR: Go version 1.18 is required for $(VERSION) of Gaia." - exit 1 -endif + all: install lint run-tests test-e2e vulncheck @@ -107,7 +102,7 @@ BUILD_TARGETS := build install build: BUILD_ARGS=-o $(BUILDDIR)/ -$(BUILD_TARGETS): check_version go.sum $(BUILDDIR)/ +$(BUILD_TARGETS): go.sum $(BUILDDIR)/ go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) ./... $(BUILDDIR)/: diff --git a/x/liquidity/keeper/liquidity_pool_test.go b/x/liquidity/keeper/liquidity_pool_test.go index 4fdf4161bc1..796c7d8dcd5 100644 --- a/x/liquidity/keeper/liquidity_pool_test.go +++ b/x/liquidity/keeper/liquidity_pool_test.go @@ -39,8 +39,8 @@ func TestCreatePool(t *testing.T) { poolTypeID := types.DefaultPoolTypeID addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) - denomA := "uETH" //nolint - denomB := "uUSD" + denomA := "uETH" //nolint:goconst // these are immediately reassigned in each case + denomB := "uUSD" //nolint:goconst // these are immediately reassigned in each case denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) From 7c5070398f09c5387a96704ea403732f1bcb5013 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Wed, 10 May 2023 05:42:50 +0700 Subject: [PATCH 21/24] tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c48af9f252b..96020d53909 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/cosmos/gaia/v9 -go 1.20 +go 1.19 require ( cosmossdk.io/math v1.0.0 From a8c4ae86d7c2de49520eb539979cef892e3c9928 Mon Sep 17 00:00:00 2001 From: Ruslan Akhtariev Date: Wed, 10 May 2023 15:38:38 +0700 Subject: [PATCH 22/24] fix --- app/test_helpers.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/test_helpers.go b/app/test_helpers.go index 7db0b47a24b..fcbbb6c1ea6 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -16,7 +16,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - appparams "github.com/cosmos/gaia/v9/app/params" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" @@ -49,7 +48,7 @@ var DefaultConsensusParams = &abci.ConsensusParams{ func setup(withGenesis bool, invCheckPeriod uint) (*GaiaApp, GenesisState) { db := dbm.NewMemDB() - encCdc := appparams.MakeTestEncodingConfig() + encCdc := MakeTestEncodingConfig() app := NewGaiaApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, invCheckPeriod, encCdc, EmptyAppOptions{}) if withGenesis { return app, NewDefaultGenesisState() From c2b374afd1f3e3f4321757ae7223e4a3937de595 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Wed, 10 May 2023 15:49:48 +0000 Subject: [PATCH 23/24] use the customized proto builder for this --- Makefile | 4 +- proto/buf.lock | 4 +- proto/buf.yaml | 3 +- proto/gaia/globalfee/v1beta1/genesis.proto | 2 +- proto/gaia/globalfee/v1beta1/query.proto | 8 +- .../liquidity/v1beta1/liquidity.proto | 820 ++++++++++-------- .../tendermint/liquidity/v1beta1/query.proto | 814 +++++++++-------- proto/tendermint/liquidity/v1beta1/tx.proto | 127 +-- third_party/proto/cosmos_proto/coin.proto | 40 - third_party/proto/cosmos_proto/cosmos.proto | 16 - x/globalfee/types/genesis.pb.go | 40 +- x/globalfee/types/query.pb.go | 50 +- 12 files changed, 972 insertions(+), 956 deletions(-) delete mode 100644 third_party/proto/cosmos_proto/coin.proto delete mode 100644 third_party/proto/cosmos_proto/cosmos.proto diff --git a/Makefile b/Makefile index 1ddb7884c0b..42e68abb54a 100644 --- a/Makefile +++ b/Makefile @@ -265,8 +265,8 @@ test-docker-push: test-docker ### Protobuf ### ############################################################################### -protoVer=0.9.0 -protoImageName=ghcr.io/cosmos/proto-builder:$(protoVer) +protoVer=latest +protoImageName=ghcr.io/faddat/proto-builder:$(protoVer) protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) proto-all: proto-format proto-lint proto-gen diff --git a/proto/buf.lock b/proto/buf.lock index 9d5c9237a75..ddc6786a250 100644 --- a/proto/buf.lock +++ b/proto/buf.lock @@ -9,8 +9,8 @@ deps: - remote: buf.build owner: cosmos repository: gogo-proto - commit: 34d970b699f84aa382f3c29773a60836 - digest: shake256:3d3bee5229ba579e7d19ffe6e140986a228b48a8c7fe74348f308537ab95e9135210e81812489d42cd8941d33ff71f11583174ccc5972e86e6112924b6ce9f04 + commit: 5e5b9fdd01804356895f8f79a6f1ddc1 + digest: shake256:0b85da49e2e5f9ebc4806eae058e2f56096ff3b1c59d1fb7c190413dd15f45dd456f0b69ced9059341c80795d2b6c943de15b120a9e0308b499e43e4b5fc2952 - remote: buf.build owner: googleapis repository: googleapis diff --git a/proto/buf.yaml b/proto/buf.yaml index 1fcdb3f996f..d0a0bfca0a6 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -6,8 +6,9 @@ version: v1beta1 deps: - buf.build/googleapis/googleapis - - buf.build/cosmos/cosmos-proto - buf.build/cosmos/gogo-proto + - buf.build/cosmos/cosmos-proto + breaking: use: diff --git a/proto/gaia/globalfee/v1beta1/genesis.proto b/proto/gaia/globalfee/v1beta1/genesis.proto index 39493b0c637..87f6a714f93 100644 --- a/proto/gaia/globalfee/v1beta1/genesis.proto +++ b/proto/gaia/globalfee/v1beta1/genesis.proto @@ -1,8 +1,8 @@ syntax = "proto3"; package gaia.globalfee.v1beta1; -import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; option go_package = "github.com/cosmos/gaia/x/globalfee/types"; diff --git a/proto/gaia/globalfee/v1beta1/query.proto b/proto/gaia/globalfee/v1beta1/query.proto index 81f587c5bd5..4cc1bdcb7d8 100644 --- a/proto/gaia/globalfee/v1beta1/query.proto +++ b/proto/gaia/globalfee/v1beta1/query.proto @@ -1,18 +1,16 @@ syntax = "proto3"; package gaia.globalfee.v1beta1; +import "cosmos/base/v1beta1/coin.proto"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; -import "cosmos/base/v1beta1/coin.proto"; option go_package = "github.com/cosmos/gaia/x/globalfee/types"; // Query defines the gRPC querier service. service Query { - rpc MinimumGasPrices(QueryMinimumGasPricesRequest) - returns (QueryMinimumGasPricesResponse) { - option (google.api.http).get = - "/gaia/globalfee/v1beta1/minimum_gas_prices"; + rpc MinimumGasPrices(QueryMinimumGasPricesRequest) returns (QueryMinimumGasPricesResponse) { + option (google.api.http).get = "/gaia/globalfee/v1beta1/minimum_gas_prices"; } } diff --git a/proto/tendermint/liquidity/v1beta1/liquidity.proto b/proto/tendermint/liquidity/v1beta1/liquidity.proto index 502248d6a3a..883a2aae90f 100644 --- a/proto/tendermint/liquidity/v1beta1/liquidity.proto +++ b/proto/tendermint/liquidity/v1beta1/liquidity.proto @@ -1,424 +1,476 @@ syntax = "proto3"; package tendermint.liquidity.v1beta1; -import "tendermint/liquidity/v1beta1/tx.proto"; +import "cosmos/base/v1beta1/coin.proto"; import "gogoproto/gogo.proto"; -import "cosmos_proto/coin.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; +import "tendermint/liquidity/v1beta1/tx.proto"; option go_package = "github.com/cosmos/gaia/v9/x/liquidity/types"; option (gogoproto.goproto_getters_all) = false; // Structure for the pool type to distinguish the characteristics of the reserve pools. message PoolType { - option (gogoproto.equal) = true; - - // This is the id of the pool_type that is used as pool_type_id for pool creation. - // In this version, only pool-type-id 1 is supported. - // {"id":1,"name":"ConstantProductLiquidityPool","min_reserve_coin_num":2,"max_reserve_coin_num":2,"description":""} - uint32 id = 1 [(gogoproto.moretags) = "yaml:\"id\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint32" - }]; - - // name of the pool type. - string name = 2 [(gogoproto.moretags) = "yaml:\"name\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"ConstantProductLiquidityPool\"", - }]; - - // minimum number of reserveCoins for LiquidityPoolType, only 2 reserve coins are supported. - uint32 min_reserve_coin_num = 3 [(gogoproto.moretags) = "yaml:\"min_reserve_coin_num\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"2\"", - format: "uint32" - }]; - - // maximum number of reserveCoins for LiquidityPoolType, only 2 reserve coins are supported. - uint32 max_reserve_coin_num = 4 [(gogoproto.moretags) = "yaml:\"max_reserve_coin_num\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"2\"", - format: "uint32" - }]; - - // description of the pool type. - string description = 5 [(gogoproto.moretags) = "yaml:\"description\""]; + option (gogoproto.equal) = true; + + // This is the id of the pool_type that is used as pool_type_id for pool creation. + // In this version, only pool-type-id 1 is supported. + // {"id":1,"name":"ConstantProductLiquidityPool","min_reserve_coin_num":2,"max_reserve_coin_num":2,"description":""} + uint32 id = 1 [ + (gogoproto.moretags) = "yaml:\"id\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint32" + } + ]; + + // name of the pool type. + string name = 2 [ + (gogoproto.moretags) = "yaml:\"name\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "\"ConstantProductLiquidityPool\""} + ]; + + // minimum number of reserveCoins for LiquidityPoolType, only 2 reserve coins are supported. + uint32 min_reserve_coin_num = 3 [ + (gogoproto.moretags) = "yaml:\"min_reserve_coin_num\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"2\"", + format: "uint32" + } + ]; + + // maximum number of reserveCoins for LiquidityPoolType, only 2 reserve coins are supported. + uint32 max_reserve_coin_num = 4 [ + (gogoproto.moretags) = "yaml:\"max_reserve_coin_num\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"2\"", + format: "uint32" + } + ]; + + // description of the pool type. + string description = 5 [(gogoproto.moretags) = "yaml:\"description\""]; } // Params defines the parameters for the liquidity module. message Params { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - // list of available pool types - repeated PoolType pool_types = 1 [ - (gogoproto.moretags) = "yaml:\"pool_types\"", - (gogoproto.nullable) = false - ]; - - // Minimum number of coins to be deposited to the liquidity pool on pool creation. - string min_init_deposit_amount = 2 [ - (gogoproto.moretags) = "yaml:\"min_init_deposit_amount\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1000000\"", - format: "sdk.Int" - }]; - - // Initial mint amount of pool coins upon pool creation. - string init_pool_coin_mint_amount = 3 [ - (gogoproto.moretags) = "yaml:\"init_pool_coin_mint_amount\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1000000\"", - format: "sdk.Int" - }]; - - // Limit the size of each liquidity pool to minimize risk. In development, set to 0 for no limit. In production, set a limit. - string max_reserve_coin_amount = 4 [ - (gogoproto.moretags) = "yaml:\"max_reserve_coin_amount\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1000000000000\"", - format: "sdk.Int" - }]; - - // Fee paid to create a Liquidity Pool. Set a fee to prevent spamming. - repeated cosmos.base.v1beta1.Coin pool_creation_fee = 5 [ - (gogoproto.moretags) = "yaml:\"pool_creation_fee\"", - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "[{\"denom\": \"uatom\", \"amount\": \"100000000\"}]", - format: "sdk.Coins" - } - ]; - - // Swap fee rate for every executed swap. - string swap_fee_rate = 6 [ - (gogoproto.moretags) = "yaml:\"swap_fee_rate\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"0.003\"", - format: "sdk.Dec" - }]; - - // Reserve coin withdrawal with less proportion by withdrawFeeRate. - string withdraw_fee_rate = 7 [ - (gogoproto.moretags) = "yaml:\"withdraw_fee_rate\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"0.003\"", - format: "sdk.Dec" - }]; - - // Maximum ratio of reserve coins that can be ordered at a swap order. - string max_order_amount_ratio = 8 [ - (gogoproto.moretags) = "yaml:\"max_order_amount_ratio\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"0.003\"", - format: "sdk.Dec" - }]; - - // The smallest unit batch height for every liquidity pool. - uint32 unit_batch_height = 9 [ - (gogoproto.moretags) = "yaml:\"unit_batch_height\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint32" - }]; - - // Circuit breaker enables or disables transaction messages in liquidity module. - bool circuit_breaker_enabled = 10 [ - (gogoproto.moretags) = "yaml:\"circuit_breaker_enabled\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"false\"", - format: "bool" - }]; + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + // list of available pool types + repeated PoolType pool_types = 1 [ + (gogoproto.moretags) = "yaml:\"pool_types\"", + (gogoproto.nullable) = false + ]; + + // Minimum number of coins to be deposited to the liquidity pool on pool creation. + string min_init_deposit_amount = 2 [ + (gogoproto.moretags) = "yaml:\"min_init_deposit_amount\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000000\"", + format: "sdk.Int" + } + ]; + + // Initial mint amount of pool coins upon pool creation. + string init_pool_coin_mint_amount = 3 [ + (gogoproto.moretags) = "yaml:\"init_pool_coin_mint_amount\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000000\"", + format: "sdk.Int" + } + ]; + + // Limit the size of each liquidity pool to minimize risk. In development, set to 0 for no limit. In production, set a limit. + string max_reserve_coin_amount = 4 [ + (gogoproto.moretags) = "yaml:\"max_reserve_coin_amount\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000000000000\"", + format: "sdk.Int" + } + ]; + + // Fee paid to create a Liquidity Pool. Set a fee to prevent spamming. + repeated cosmos.base.v1beta1.Coin pool_creation_fee = 5 [ + (gogoproto.moretags) = "yaml:\"pool_creation_fee\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "[{\"denom\": \"uatom\", \"amount\": \"100000000\"}]", + format: "sdk.Coins" + } + ]; + + // Swap fee rate for every executed swap. + string swap_fee_rate = 6 [ + (gogoproto.moretags) = "yaml:\"swap_fee_rate\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"0.003\"", + format: "sdk.Dec" + } + ]; + + // Reserve coin withdrawal with less proportion by withdrawFeeRate. + string withdraw_fee_rate = 7 [ + (gogoproto.moretags) = "yaml:\"withdraw_fee_rate\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"0.003\"", + format: "sdk.Dec" + } + ]; + + // Maximum ratio of reserve coins that can be ordered at a swap order. + string max_order_amount_ratio = 8 [ + (gogoproto.moretags) = "yaml:\"max_order_amount_ratio\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"0.003\"", + format: "sdk.Dec" + } + ]; + + // The smallest unit batch height for every liquidity pool. + uint32 unit_batch_height = 9 [ + (gogoproto.moretags) = "yaml:\"unit_batch_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint32" + } + ]; + + // Circuit breaker enables or disables transaction messages in liquidity module. + bool circuit_breaker_enabled = 10 [ + (gogoproto.moretags) = "yaml:\"circuit_breaker_enabled\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"false\"", + format: "bool" + } + ]; } // Pool defines the liquidity pool that contains pool information. message Pool { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = true; - - // id of the pool - uint64 id = 1 [(gogoproto.moretags) = "yaml:\"id\"", (gogoproto.jsontag) = "id", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // id of the pool_type - uint32 type_id = 2 [(gogoproto.moretags) = "yaml:\"type_id\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint32" - }]; - - // denoms of reserve coin pair of the pool - repeated string reserve_coin_denoms = 3 [(gogoproto.moretags) = "yaml:\"reserve_coin_denoms\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "[\"denomX\",\"denomY\"]" - }]; - - // reserve account address of the pool - string reserve_account_address = 4 [(gogoproto.moretags) = "yaml:\"reserve_account_address\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"cosmos16ddqestwukv0jzcyfn3fdfq9h2wrs83cr4rfm3\"", - format: "sdk.AccAddress" - }]; - - // denom of pool coin of the pool - string pool_coin_denom = 5 [(gogoproto.moretags) = "yaml:\"pool_coin_denom\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4\"", - }]; + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = true; + + // id of the pool + uint64 id = 1 [ + (gogoproto.moretags) = "yaml:\"id\"", + (gogoproto.jsontag) = "id", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // id of the pool_type + uint32 type_id = 2 [ + (gogoproto.moretags) = "yaml:\"type_id\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint32" + } + ]; + + // denoms of reserve coin pair of the pool + repeated string reserve_coin_denoms = 3 [ + (gogoproto.moretags) = "yaml:\"reserve_coin_denoms\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "[\"denomX\",\"denomY\"]"} + ]; + + // reserve account address of the pool + string reserve_account_address = 4 [ + (gogoproto.moretags) = "yaml:\"reserve_account_address\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"cosmos16ddqestwukv0jzcyfn3fdfq9h2wrs83cr4rfm3\"", + format: "sdk.AccAddress" + } + ]; + + // denom of pool coin of the pool + string pool_coin_denom = 5 [ + (gogoproto.moretags) = "yaml:\"pool_coin_denom\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "\"poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4\""} + ]; } // Metadata for the state of each pool for invariant checking after genesis export or import. message PoolMetadata { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = true; - - // id of the pool - uint64 pool_id = 1 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // pool coin issued at the pool - cosmos.base.v1beta1.Coin pool_coin_total_supply = 2 [ - (gogoproto.moretags) = "yaml:\"pool_coin_total_supply\"", - (gogoproto.nullable) = false, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "{\"denom\": \"poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4\", \"amount\": \"1000000\"}", - format: "sdk.Coin" - }]; - - // reserve coins deposited in the pool - repeated cosmos.base.v1beta1.Coin reserve_coins = 3 [ - (gogoproto.moretags) = "yaml:\"reserve_coins\"", - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "[{\"denom\": \"denomX\", \"amount\": \"1000000\"}, {\"denom\": \"denomY\", \"amount\": \"2000000\"}]", - format: "sdk.Coins" - }]; + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = true; + + // id of the pool + uint64 pool_id = 1 [ + (gogoproto.moretags) = "yaml:\"pool_id\"", + (gogoproto.jsontag) = "pool_id", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // pool coin issued at the pool + cosmos.base.v1beta1.Coin pool_coin_total_supply = 2 [ + (gogoproto.moretags) = "yaml:\"pool_coin_total_supply\"", + (gogoproto.nullable) = false, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4\", \"amount\": \"1000000\"}", + format: "sdk.Coin" + } + ]; + + // reserve coins deposited in the pool + repeated cosmos.base.v1beta1.Coin reserve_coins = 3 [ + (gogoproto.moretags) = "yaml:\"reserve_coins\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "[{\"denom\": \"denomX\", \"amount\": \"1000000\"}, {\"denom\": \"denomY\", \"amount\": \"2000000\"}]", + format: "sdk.Coins" + } + ]; } -// PoolBatch defines the batch or batches of a given liquidity pool that contains indexes of deposit, withdraw, and swap messages. +// PoolBatch defines the batch or batches of a given liquidity pool that contains indexes of deposit, withdraw, and swap messages. // Index param increments by 1 if the pool id is same. message PoolBatch { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = true; - - // id of the pool - uint64 pool_id = 1 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // index of this batch - uint64 index = 2 [(gogoproto.moretags) = "yaml:\"index\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // height where this batch is started - int64 begin_height = 3 [(gogoproto.moretags) = "yaml:\"begin_height\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1000\"", - format: "int64" - }]; - - // last index of DepositMsgStates - uint64 deposit_msg_index = 4 [(gogoproto.moretags) = "yaml:\"deposit_msg_index\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // last index of WithdrawMsgStates - uint64 withdraw_msg_index = 5 [(gogoproto.moretags) = "yaml:\"withdraw_msg_index\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // last index of SwapMsgStates - uint64 swap_msg_index = 6 [(gogoproto.moretags) = "yaml:\"swap_msg_index\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // true if executed, false if not executed - bool executed = 7 [(gogoproto.moretags) = "yaml:\"executed\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = true; + + // id of the pool + uint64 pool_id = 1 [ + (gogoproto.moretags) = "yaml:\"pool_id\"", + (gogoproto.jsontag) = "pool_id", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // index of this batch + uint64 index = 2 [ + (gogoproto.moretags) = "yaml:\"index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // height where this batch is started + int64 begin_height = 3 [ + (gogoproto.moretags) = "yaml:\"begin_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + } + ]; + + // last index of DepositMsgStates + uint64 deposit_msg_index = 4 [ + (gogoproto.moretags) = "yaml:\"deposit_msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // last index of WithdrawMsgStates + uint64 withdraw_msg_index = 5 [ + (gogoproto.moretags) = "yaml:\"withdraw_msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // last index of SwapMsgStates + uint64 swap_msg_index = 6 [ + (gogoproto.moretags) = "yaml:\"swap_msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // true if executed, false if not executed + bool executed = 7 [ + (gogoproto.moretags) = "yaml:\"executed\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; } // DepositMsgState defines the state of deposit message that contains state information as it is processed in the next batch or batches. message DepositMsgState { - - // height where this message is appended to the batch - int64 msg_height = 1 [(gogoproto.moretags) = "yaml:\"msg_height\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1000\"", - format: "int64" - }]; - - // index of this deposit message in this liquidity pool - uint64 msg_index = 2 [(gogoproto.moretags) = "yaml:\"msg_index\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // true if executed on this batch, false if not executed - bool executed = 3 [(gogoproto.moretags) = "yaml:\"executed\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; - - // true if executed successfully on this batch, false if failed - bool succeeded = 4 [(gogoproto.moretags) = "yaml:\"succeeded\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; - - // true if ready to be deleted on kvstore, false if not ready to be deleted - bool to_be_deleted = 5 [(gogoproto.moretags) = "yaml:\"to_be_deleted\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; - - // MsgDepositWithinBatch - MsgDepositWithinBatch msg = 6 [(gogoproto.moretags) = "yaml:\"msg\""]; + // height where this message is appended to the batch + int64 msg_height = 1 [ + (gogoproto.moretags) = "yaml:\"msg_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + } + ]; + + // index of this deposit message in this liquidity pool + uint64 msg_index = 2 [ + (gogoproto.moretags) = "yaml:\"msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // true if executed on this batch, false if not executed + bool executed = 3 [ + (gogoproto.moretags) = "yaml:\"executed\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; + + // true if executed successfully on this batch, false if failed + bool succeeded = 4 [ + (gogoproto.moretags) = "yaml:\"succeeded\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; + + // true if ready to be deleted on kvstore, false if not ready to be deleted + bool to_be_deleted = 5 [ + (gogoproto.moretags) = "yaml:\"to_be_deleted\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; + + // MsgDepositWithinBatch + MsgDepositWithinBatch msg = 6 [(gogoproto.moretags) = "yaml:\"msg\""]; } // WithdrawMsgState defines the state of the withdraw message that contains state information as the message is processed in the next batch or batches. message WithdrawMsgState { - - // height where this message is appended to the batch - int64 msg_height = 1 [(gogoproto.moretags) = "yaml:\"msg_height\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1000\"", - format: "int64" - }]; - - // index of this withdraw message in this liquidity pool - uint64 msg_index = 2 [(gogoproto.moretags) = "yaml:\"msg_index\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // true if executed on this batch, false if not executed - bool executed = 3 [(gogoproto.moretags) = "yaml:\"executed\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; - - // true if executed successfully on this batch, false if failed - bool succeeded = 4 [(gogoproto.moretags) = "yaml:\"succeeded\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; - - // true if ready to be deleted on kvstore, false if not ready to be deleted - bool to_be_deleted = 5 [(gogoproto.moretags) = "yaml:\"to_be_deleted\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; - - // MsgWithdrawWithinBatch - MsgWithdrawWithinBatch msg = 6 [(gogoproto.moretags) = "yaml:\"msg\""]; + // height where this message is appended to the batch + int64 msg_height = 1 [ + (gogoproto.moretags) = "yaml:\"msg_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + } + ]; + + // index of this withdraw message in this liquidity pool + uint64 msg_index = 2 [ + (gogoproto.moretags) = "yaml:\"msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // true if executed on this batch, false if not executed + bool executed = 3 [ + (gogoproto.moretags) = "yaml:\"executed\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; + + // true if executed successfully on this batch, false if failed + bool succeeded = 4 [ + (gogoproto.moretags) = "yaml:\"succeeded\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; + + // true if ready to be deleted on kvstore, false if not ready to be deleted + bool to_be_deleted = 5 [ + (gogoproto.moretags) = "yaml:\"to_be_deleted\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; + + // MsgWithdrawWithinBatch + MsgWithdrawWithinBatch msg = 6 [(gogoproto.moretags) = "yaml:\"msg\""]; } // SwapMsgState defines the state of the swap message that contains state information as the message is processed in the next batch or batches. message SwapMsgState { - - // height where this message is appended to the batch - int64 msg_height = 1 [(gogoproto.moretags) = "yaml:\"msg_height\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1000\"", - format: "int64" - }]; - - // index of this swap message in this liquidity pool - uint64 msg_index = 2 [(gogoproto.moretags) = "yaml:\"msg_index\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1\"", - format: "uint64" - }]; - - // true if executed on this batch, false if not executed - bool executed = 3 [(gogoproto.moretags) = "yaml:\"executed\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; - - // true if executed successfully on this batch, false if failed - bool succeeded = 4 [(gogoproto.moretags) = "yaml:\"succeeded\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; - - // true if ready to be deleted on kvstore, false if not ready to be deleted - bool to_be_deleted = 5 [(gogoproto.moretags) = "yaml:\"to_be_deleted\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "true", - }]; - - // swap orders are cancelled when current height is equal to or higher than ExpiryHeight - int64 order_expiry_height = 6 [(gogoproto.moretags) = "yaml:\"order_expiry_height\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"1000\"", - format: "int64" - }]; - - // offer coin exchanged until now - cosmos.base.v1beta1.Coin exchanged_offer_coin = 7 [ - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"exchanged_offer_coin\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "{\"denom\": \"denomX\", \"amount\": \"600000\"}", - format: "sdk.Coin" - }]; - - // offer coin currently remaining to be exchanged - cosmos.base.v1beta1.Coin remaining_offer_coin = 8 [ - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"remaining_offer_coin\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "{\"denom\": \"denomX\", \"amount\": \"400000\"}", - format: "sdk.Coin" - }]; - - // reserve fee for pays fee in half offer coin - cosmos.base.v1beta1.Coin reserved_offer_coin_fee = 9 [ - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"reserved_offer_coin_fee\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "{\"denom\": \"denomX\", \"amount\": \"5000\"}", - format: "sdk.Coin" - } - ]; - - // MsgSwapWithinBatch - MsgSwapWithinBatch msg = 10 [(gogoproto.moretags) = "yaml:\"msg\""]; + // height where this message is appended to the batch + int64 msg_height = 1 [ + (gogoproto.moretags) = "yaml:\"msg_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + } + ]; + + // index of this swap message in this liquidity pool + uint64 msg_index = 2 [ + (gogoproto.moretags) = "yaml:\"msg_index\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1\"", + format: "uint64" + } + ]; + + // true if executed on this batch, false if not executed + bool executed = 3 [ + (gogoproto.moretags) = "yaml:\"executed\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; + + // true if executed successfully on this batch, false if failed + bool succeeded = 4 [ + (gogoproto.moretags) = "yaml:\"succeeded\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; + + // true if ready to be deleted on kvstore, false if not ready to be deleted + bool to_be_deleted = 5 [ + (gogoproto.moretags) = "yaml:\"to_be_deleted\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "true"} + ]; + + // swap orders are cancelled when current height is equal to or higher than ExpiryHeight + int64 order_expiry_height = 6 [ + (gogoproto.moretags) = "yaml:\"order_expiry_height\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"1000\"", + format: "int64" + } + ]; + + // offer coin exchanged until now + cosmos.base.v1beta1.Coin exchanged_offer_coin = 7 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"exchanged_offer_coin\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"denomX\", \"amount\": \"600000\"}", + format: "sdk.Coin" + } + ]; + + // offer coin currently remaining to be exchanged + cosmos.base.v1beta1.Coin remaining_offer_coin = 8 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"remaining_offer_coin\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"denomX\", \"amount\": \"400000\"}", + format: "sdk.Coin" + } + ]; + + // reserve fee for pays fee in half offer coin + cosmos.base.v1beta1.Coin reserved_offer_coin_fee = 9 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"reserved_offer_coin_fee\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "{\"denom\": \"denomX\", \"amount\": \"5000\"}", + format: "sdk.Coin" + } + ]; + + // MsgSwapWithinBatch + MsgSwapWithinBatch msg = 10 [(gogoproto.moretags) = "yaml:\"msg\""]; } diff --git a/proto/tendermint/liquidity/v1beta1/query.proto b/proto/tendermint/liquidity/v1beta1/query.proto index 9eeb66620de..f07295b4391 100644 --- a/proto/tendermint/liquidity/v1beta1/query.proto +++ b/proto/tendermint/liquidity/v1beta1/query.proto @@ -1,416 +1,413 @@ syntax = "proto3"; package tendermint.liquidity.v1beta1; +import "cosmos_proto/pagination.proto"; import "gogoproto/gogo.proto"; -import "tendermint/liquidity/v1beta1/liquidity.proto"; import "google/api/annotations.proto"; -import "cosmos_proto/pagination.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; +import "tendermint/liquidity/v1beta1/liquidity.proto"; option go_package = "github.com/cosmos/gaia/v9/x/liquidity/types"; // Query defines the gRPC query service for the liquidity module. service Query { - // Get existing liquidity pools. - rpc LiquidityPools (QueryLiquidityPoolsRequest) returns (QueryLiquidityPoolsResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns a list of all liquidity pools with pagination result."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"code":2,"message":"rpc error: code = NotFound desc = There are no pools present.: key not found","details":[]}' - } - } - } - }; - } - - // Get specific liquidity pool. - rpc LiquidityPool (QueryLiquidityPoolRequest) returns (QueryLiquidityPoolResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns the liquidity pool that corresponds to the pool_id."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' - } - } - } - responses: { - key: "400" - value: { - description: "Bad Request" - examples: { - key: "application/json" - value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' - } - } - } - }; - } - - // Get specific liquidity pool corresponding to the pool_coin_denom. - rpc LiquidityPoolByPoolCoinDenom (QueryLiquidityPoolByPoolCoinDenomRequest) returns (QueryLiquidityPoolResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/pool_coin_denom/{pool_coin_denom}"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "It returns the liquidity pool corresponding to the pool_coin_denom."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"code":2,"message":"rpc error: code = NotFound desc = the liquidity pool corresponding to the pool_coin_denom doesn\'t exist: key not found","details":[]}' - } - } - } - responses: { - key: "404" - value: { - description: "Not Found" - examples: { - key: "application/json" - value: '{"code":5,"message":"rpc error: code = NotFound desc = liquidity pool with pool coin denom xx doesn\'t exist: key not found","details":[]}' - } - } - } - }; - } - - - // Get specific liquidity pool corresponding to the reserve account. - rpc LiquidityPoolByReserveAcc (QueryLiquidityPoolByReserveAccRequest) returns (QueryLiquidityPoolResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/reserve_acc/{reserve_acc}"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "It returns the liquidity pool corresponding to the reserve account."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"code":2,"message":"rpc error: code = NotFound desc = the liquidity pool corresponding to the reserve account doesn\'t exist: key not found","details":[]}' - } - } - } - responses: { - key: "404" - value: { - description: "Not Found" - examples: { - key: "application/json" - value: '{"code":5,"message":"rpc error: code = NotFound desc = the reserve account address xx is not valid: key not found","details":[]}' - } - } - } - }; - } - - // Get the pool's current batch. - rpc LiquidityPoolBatch (QueryLiquidityPoolBatchRequest) returns (QueryLiquidityPoolBatchResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns the current batch of the pool that corresponds to the pool_id."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' - } - } - } - responses: { - key: "400" - value: { - description: "Bad Request" - examples: { - key: "application/json" - value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' - } - } - } - }; - } - - // Get all swap messages in the pool's current batch. - rpc PoolBatchSwapMsgs(QueryPoolBatchSwapMsgsRequest) returns (QueryPoolBatchSwapMsgsResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/swaps"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns a list of all swap messages in the current batch of the pool with pagination result."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' - } - } - } - responses: { - key: "400" - value: { - description: "Bad Request" - examples: { - key: "application/json" - value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' - } - } - } - }; - } - - // Get a specific swap message in the pool's current batch. - rpc PoolBatchSwapMsg(QueryPoolBatchSwapMsgRequest) returns (QueryPoolBatchSwapMsgResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/swaps/{msg_index}"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns the swap message that corresponds to the msg_index in the pool's current batch"; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"root":{"code":2,"details":[],"message":"rpc error: code = NotFound desc = the msg given msg_index 1 doesn\'t exist or deleted: key not found"}}' - } - } - } - responses: { - key: "400" - value: { - description: "Bad Request" - examples: { - key: "application/json" - value: '{"code":3,"message":"type mismatch, parameter: msg_index, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' - } - } - } - }; - } - - // Get all deposit messages in the pool's current batch. - rpc PoolBatchDepositMsgs(QueryPoolBatchDepositMsgsRequest) returns (QueryPoolBatchDepositMsgsResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/deposits"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns a list of all deposit messages in the current batch of the pool with pagination result."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' - } - } - } - responses: { - key: "400" - value: { - description: "Bad Request" - examples: { - key: "application/json" - value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' - } - } - } - - }; - } - - // Get a specific deposit message in the pool's current batch. - rpc PoolBatchDepositMsg(QueryPoolBatchDepositMsgRequest) returns (QueryPoolBatchDepositMsgResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/deposits/{msg_index}"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns the deposit message that corresponds to the msg_index in the pool's current batch."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"root":{"code":2,"details":[],"message":"rpc error: code = NotFound desc = the msg given msg_index 1 doesn\'t exist or deleted: key not found"}}' - } - } - } - responses: { - key: "400" - value: { - description: "Bad Request" - examples: { - key: "application/json" - value: '{"code":3,"message":"type mismatch, parameter: msg_index, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' - } - } - } - }; - } - - // Get all withdraw messages in the pool's current batch. - rpc PoolBatchWithdrawMsgs(QueryPoolBatchWithdrawMsgsRequest) returns (QueryPoolBatchWithdrawMsgsResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/withdraws"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns a list of all withdraw messages in the current batch of the pool with pagination result."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' - } - } - } - responses: { - key: "400" - value: { - description: "Bad Request" - examples: { - key: "application/json" - value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' - } - } - } - - }; - } - - // Get a specific withdraw message in the pool's current batch. - rpc PoolBatchWithdrawMsg(QueryPoolBatchWithdrawMsgRequest) returns (QueryPoolBatchWithdrawMsgResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/withdraws/{msg_index}"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns the withdraw message that corresponds to the msg_index in the pool's current batch."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; - description: "Find out more about the query and error codes"; - } - responses: { - key: "500" - value: { - description: "Internal Server Error" - examples: { - key: "application/json" - value: '{"root":{"code":2,"details":[],"message":"rpc error: code = NotFound desc = the msg given msg_index 1 doesn\'t exist or deleted: key not found"}}' - } - } - } - responses: { - key: "400" - value: { - description: "Bad Request" - examples: { - key: "application/json" - value: '{"code":3,"message":"type mismatch, parameter: msg_index, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' - } - } - } - }; - } - - // Get all parameters of the liquidity module. - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { - option (google.api.http).get = "/cosmos/liquidity/v1beta1/params"; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - description: "Returns all parameters of the liquidity module."; - external_docs: { - url: "https://github.com/tendermint/liquidity/blob/develop/x/liquidity/spec/08_params.md"; - description: "Find out more about the params"; - } - }; - } + // Get existing liquidity pools. + rpc LiquidityPools(QueryLiquidityPoolsRequest) returns (QueryLiquidityPoolsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns a list of all liquidity pools with pagination result."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = There are no pools present.: key not found","details":[]}' + } + } + } + }; + } + + // Get specific liquidity pool. + rpc LiquidityPool(QueryLiquidityPoolRequest) returns (QueryLiquidityPoolResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the liquidity pool that corresponds to the pool_id."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get specific liquidity pool corresponding to the pool_coin_denom. + rpc LiquidityPoolByPoolCoinDenom(QueryLiquidityPoolByPoolCoinDenomRequest) returns (QueryLiquidityPoolResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/pool_coin_denom/{pool_coin_denom}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "It returns the liquidity pool corresponding to the pool_coin_denom."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = the liquidity pool corresponding to the pool_coin_denom doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "404" + value: { + description: "Not Found" + examples: { + key: "application/json" + value: '{"code":5,"message":"rpc error: code = NotFound desc = liquidity pool with pool coin denom xx doesn\'t exist: key not found","details":[]}' + } + } + } + }; + } + + // Get specific liquidity pool corresponding to the reserve account. + rpc LiquidityPoolByReserveAcc(QueryLiquidityPoolByReserveAccRequest) returns (QueryLiquidityPoolResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/reserve_acc/{reserve_acc}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "It returns the liquidity pool corresponding to the reserve account."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = the liquidity pool corresponding to the reserve account doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "404" + value: { + description: "Not Found" + examples: { + key: "application/json" + value: '{"code":5,"message":"rpc error: code = NotFound desc = the reserve account address xx is not valid: key not found","details":[]}' + } + } + } + }; + } + + // Get the pool's current batch. + rpc LiquidityPoolBatch(QueryLiquidityPoolBatchRequest) returns (QueryLiquidityPoolBatchResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the current batch of the pool that corresponds to the pool_id."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get all swap messages in the pool's current batch. + rpc PoolBatchSwapMsgs(QueryPoolBatchSwapMsgsRequest) returns (QueryPoolBatchSwapMsgsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/swaps"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns a list of all swap messages in the current batch of the pool with pagination result."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get a specific swap message in the pool's current batch. + rpc PoolBatchSwapMsg(QueryPoolBatchSwapMsgRequest) returns (QueryPoolBatchSwapMsgResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/swaps/{msg_index}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the swap message that corresponds to the msg_index in the pool's current batch"; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"root":{"code":2,"details":[],"message":"rpc error: code = NotFound desc = the msg given msg_index 1 doesn\'t exist or deleted: key not found"}}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: msg_index, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get all deposit messages in the pool's current batch. + rpc PoolBatchDepositMsgs(QueryPoolBatchDepositMsgsRequest) returns (QueryPoolBatchDepositMsgsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/deposits"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns a list of all deposit messages in the current batch of the pool with pagination result."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get a specific deposit message in the pool's current batch. + rpc PoolBatchDepositMsg(QueryPoolBatchDepositMsgRequest) returns (QueryPoolBatchDepositMsgResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/deposits/{msg_index}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the deposit message that corresponds to the msg_index in the pool's current batch."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"root":{"code":2,"details":[],"message":"rpc error: code = NotFound desc = the msg given msg_index 1 doesn\'t exist or deleted: key not found"}}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: msg_index, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get all withdraw messages in the pool's current batch. + rpc PoolBatchWithdrawMsgs(QueryPoolBatchWithdrawMsgsRequest) returns (QueryPoolBatchWithdrawMsgsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/withdraws"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns a list of all withdraw messages in the current batch of the pool with pagination result."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"code":2,"message":"rpc error: code = NotFound desc = liquidity pool 3 doesn\'t exist: key not found","details":[]}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: pool_id, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get a specific withdraw message in the pool's current batch. + rpc PoolBatchWithdrawMsg(QueryPoolBatchWithdrawMsgRequest) returns (QueryPoolBatchWithdrawMsgResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/pools/{pool_id}/batch/withdraws/{msg_index}"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns the withdraw message that corresponds to the msg_index in the pool's current batch."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/doc/client.md"; + description: "Find out more about the query and error codes"; + } + responses: { + key: "500" + value: { + description: "Internal Server Error" + examples: { + key: "application/json" + value: '{"root":{"code":2,"details":[],"message":"rpc error: code = NotFound desc = the msg given msg_index 1 doesn\'t exist or deleted: key not found"}}' + } + } + } + responses: { + key: "400" + value: { + description: "Bad Request" + examples: { + key: "application/json" + value: '{"code":3,"message":"type mismatch, parameter: msg_index, error: strconv.ParseUint: parsing *: invalid syntax","details":[]}' + } + } + } + }; + } + + // Get all parameters of the liquidity module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/cosmos/liquidity/v1beta1/params"; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + description: "Returns all parameters of the liquidity module."; + external_docs: { + url: "https://github.com/tendermint/liquidity/blob/develop/x/liquidity/spec/08_params.md"; + description: "Find out more about the params"; + } + }; + } } // the request type for the QueryLiquidityPool RPC method. requestable specified pool_id. message QueryLiquidityPoolRequest { - uint64 pool_id = 1; + uint64 pool_id = 1; } // the response type for the QueryLiquidityPoolResponse RPC method. Returns the liquidity pool that corresponds to the requested pool_id. message QueryLiquidityPoolResponse { - Pool pool = 1 [(gogoproto.nullable) = false]; + Pool pool = 1 [(gogoproto.nullable) = false]; } // the request type for the QueryLiquidityByPoolCoinDenomPool RPC method. Requestable specified pool_coin_denom. message QueryLiquidityPoolByPoolCoinDenomRequest { - string pool_coin_denom = 1; + string pool_coin_denom = 1; } // the request type for the QueryLiquidityByReserveAcc RPC method. Requestable specified reserve_acc. message QueryLiquidityPoolByReserveAccRequest { - string reserve_acc = 1; + string reserve_acc = 1; } // the request type for the QueryLiquidityPoolBatch RPC method. requestable including specified pool_id. message QueryLiquidityPoolBatchRequest { - // id of the target pool for query - uint64 pool_id = 1; + // id of the target pool for query + uint64 pool_id = 1; } // the response type for the QueryLiquidityPoolBatchResponse RPC method. Returns the liquidity pool batch that corresponds to the requested pool_id. message QueryLiquidityPoolBatchResponse { - PoolBatch batch = 1 [(gogoproto.nullable) = false]; + PoolBatch batch = 1 [(gogoproto.nullable) = false]; } // the request type for the QueryLiquidityPools RPC method. Requestable including pagination offset, limit, key. message QueryLiquidityPoolsRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; } // the response type for the QueryLiquidityPoolsResponse RPC method. This includes a list of all existing liquidity pools and paging results that contain next_key and total count. message QueryLiquidityPoolsResponse { - repeated Pool pools = 1 [(gogoproto.nullable) = false]; - // pagination defines the pagination in the response. not working on this version. - cosmos.base.query.v1beta1.PageResponse pagination = 2; + repeated Pool pools = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. not working on this version. + cosmos.base.query.v1beta1.PageResponse pagination = 2; } // QueryParamsRequest is request type for the QueryParams RPC method. @@ -418,91 +415,90 @@ message QueryParamsRequest {} // the response type for the QueryParamsResponse RPC method. This includes current parameter of the liquidity module. message QueryParamsResponse { - // params holds all the parameters of this module. - Params params = 1 [(gogoproto.nullable) = false]; + // params holds all the parameters of this module. + Params params = 1 [(gogoproto.nullable) = false]; } // the request type for the QueryPoolBatchSwapMsgs RPC method. Requestable including specified pool_id and pagination offset, limit, key. message QueryPoolBatchSwapMsgsRequest { - // id of the target pool for query - uint64 pool_id = 1; - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 2; + // id of the target pool for query + uint64 pool_id = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; } // the request type for the QueryPoolBatchSwap RPC method. Requestable including specified pool_id and msg_index. message QueryPoolBatchSwapMsgRequest { - // id of the target pool for query - uint64 pool_id = 1; - // target msg_index of the pool - uint64 msg_index = 2; + // id of the target pool for query + uint64 pool_id = 1; + // target msg_index of the pool + uint64 msg_index = 2; } // the response type for the QueryPoolBatchSwapMsgs RPC method. This includes list of all currently existing swap messages of the batch and paging results that contain next_key and total count. message QueryPoolBatchSwapMsgsResponse { - repeated SwapMsgState swaps = 1 [(gogoproto.nullable) = false]; - // pagination defines the pagination in the response. not working on this version. - cosmos.base.query.v1beta1.PageResponse pagination = 2; + repeated SwapMsgState swaps = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. not working on this version. + cosmos.base.query.v1beta1.PageResponse pagination = 2; } // the response type for the QueryPoolBatchSwapMsg RPC method. This includes a batch swap message of the batch. message QueryPoolBatchSwapMsgResponse { - SwapMsgState swap = 1 [(gogoproto.nullable) = false]; + SwapMsgState swap = 1 [(gogoproto.nullable) = false]; } // the request type for the QueryPoolBatchDeposit RPC method. Requestable including specified pool_id and pagination offset, limit, key. message QueryPoolBatchDepositMsgsRequest { - // id of the target pool for query - uint64 pool_id = 1; - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 2; + // id of the target pool for query + uint64 pool_id = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; } // the request type for the QueryPoolBatchDeposit RPC method. requestable including specified pool_id and msg_index. message QueryPoolBatchDepositMsgRequest { - // id of the target pool for query - uint64 pool_id = 1; - // target msg_index of the pool - uint64 msg_index = 2; + // id of the target pool for query + uint64 pool_id = 1; + // target msg_index of the pool + uint64 msg_index = 2; } // the response type for the QueryPoolBatchDeposit RPC method. This includes a list of all currently existing deposit messages of the batch and paging results that contain next_key and total count. message QueryPoolBatchDepositMsgsResponse { - repeated DepositMsgState deposits = 1 [(gogoproto.nullable) = false]; - // pagination defines the pagination in the response. not working on this version. - cosmos.base.query.v1beta1.PageResponse pagination = 2; + repeated DepositMsgState deposits = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. not working on this version. + cosmos.base.query.v1beta1.PageResponse pagination = 2; } // the response type for the QueryPoolBatchDepositMsg RPC method. This includes a batch swap message of the batch. message QueryPoolBatchDepositMsgResponse { - DepositMsgState deposit = 1 [(gogoproto.nullable) = false]; + DepositMsgState deposit = 1 [(gogoproto.nullable) = false]; } - // the request type for the QueryPoolBatchWithdraw RPC method. Requestable including specified pool_id and pagination offset, limit, key. message QueryPoolBatchWithdrawMsgsRequest { - // id of the target pool for query - uint64 pool_id = 1; - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 2; + // id of the target pool for query + uint64 pool_id = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; } // the request type for the QueryPoolBatchWithdraw RPC method. requestable including specified pool_id and msg_index. message QueryPoolBatchWithdrawMsgRequest { - // id of the target pool for query - uint64 pool_id = 1; - // target msg_index of the pool - uint64 msg_index = 2; + // id of the target pool for query + uint64 pool_id = 1; + // target msg_index of the pool + uint64 msg_index = 2; } // the response type for the QueryPoolBatchWithdraw RPC method. This includes a list of all currently existing withdraw messages of the batch and paging results that contain next_key and total count. message QueryPoolBatchWithdrawMsgsResponse { - repeated WithdrawMsgState withdraws = 1 [(gogoproto.nullable) = false]; - // pagination defines the pagination in the response. Not supported on this version. - cosmos.base.query.v1beta1.PageResponse pagination = 2; + repeated WithdrawMsgState withdraws = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. Not supported on this version. + cosmos.base.query.v1beta1.PageResponse pagination = 2; } // the response type for the QueryPoolBatchWithdrawMsg RPC method. This includes a batch swap message of the batch. message QueryPoolBatchWithdrawMsgResponse { - WithdrawMsgState withdraw = 1 [(gogoproto.nullable) = false]; + WithdrawMsgState withdraw = 1 [(gogoproto.nullable) = false]; } diff --git a/proto/tendermint/liquidity/v1beta1/tx.proto b/proto/tendermint/liquidity/v1beta1/tx.proto index 3f5744c26e9..3ec9bcce412 100644 --- a/proto/tendermint/liquidity/v1beta1/tx.proto +++ b/proto/tendermint/liquidity/v1beta1/tx.proto @@ -1,15 +1,14 @@ syntax = "proto3"; package tendermint.liquidity.v1beta1; +import "cosmos/base/v1beta1/coin.proto"; import "gogoproto/gogo.proto"; -import "cosmos_proto/coin.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; option go_package = "github.com/cosmos/gaia/v9/x/liquidity/types"; // Msg defines the liquidity Msg service. service Msg { - // Submit a create liquidity pool message. rpc CreatePool(MsgCreatePool) returns (MsgCreatePoolResponse); @@ -27,61 +26,72 @@ service Msg { // // See: https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md message MsgCreatePool { - option (gogoproto.equal) = false; + option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; - string pool_creator_address = 1 [(gogoproto.moretags) = "yaml:\"pool_creator_address\"", + string pool_creator_address = 1 [ + (gogoproto.moretags) = "yaml:\"pool_creator_address\"", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "account address of the origin of this message", example: "\"cosmos1e35y69rhrt7y4yce5l5u73sjnxu0l33wvznyun\"", format: "sdk.AccAddress" - }]; + } + ]; // id of the target pool type, must match the value in the pool. Only pool-type-id 1 is supported. - uint32 pool_type_id = 2 [(gogoproto.moretags) = "yaml:\"pool_type_id\"", + uint32 pool_type_id = 2 [ + (gogoproto.moretags) = "yaml:\"pool_type_id\"", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"1\"", format: "uint32" - }]; + } + ]; // reserve coin pair of the pool to deposit. - repeated cosmos.base.v1beta1.Coin deposit_coins = 4 [(gogoproto.nullable) = false, + repeated cosmos.base.v1beta1.Coin deposit_coins = 4 [ + (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"deposit_coins\"", (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "[{\"denom\": \"denomX\", \"amount\": \"1000000\"}, {\"denom\": \"denomY\", \"amount\": \"2000000\"}]", format: "sdk.Coins" - }]; + } + ]; } // MsgCreatePoolResponse defines the Msg/CreatePool response type. message MsgCreatePoolResponse {} -// `MsgDepositWithinBatch defines` an `sdk.Msg` type that supports submitting +// `MsgDepositWithinBatch defines` an `sdk.Msg` type that supports submitting // a deposit request to the batch of the liquidity pool. -// Deposit is submitted to the batch of the Liquidity pool with the specified +// Deposit is submitted to the batch of the Liquidity pool with the specified // `pool_id`, `deposit_coins` for reserve. -// This request is stacked in the batch of the liquidity pool, is not processed +// This request is stacked in the batch of the liquidity pool, is not processed // immediately, and is processed in the `endblock` at the same time as other requests. // // See: https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md message MsgDepositWithinBatch { - option (gogoproto.equal) = false; + option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; - string depositor_address = 1 [(gogoproto.moretags) = "yaml:\"depositor_address\"", + string depositor_address = 1 [ + (gogoproto.moretags) = "yaml:\"depositor_address\"", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "account address of the origin of this message", example: "\"cosmos1e35y69rhrt7y4yce5l5u73sjnxu0l33wvznyun\"", format: "sdk.AccAddress" - }]; + } + ]; // id of the target pool - uint64 pool_id = 2 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", + uint64 pool_id = 2 [ + (gogoproto.moretags) = "yaml:\"pool_id\"", + (gogoproto.jsontag) = "pool_id", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"1\"", format: "uint64" - }]; + } + ]; // reserve coin pair of the pool to deposit repeated cosmos.base.v1beta1.Coin deposit_coins = 3 [ @@ -91,44 +101,50 @@ message MsgDepositWithinBatch { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "[{\"denom\": \"denomX\", \"amount\": \"1000000\"}, {\"denom\": \"denomY\", \"amount\": \"2000000\"}]", format: "sdk.Coins" - }]; - + } + ]; } // MsgDepositWithinBatchResponse defines the Msg/DepositWithinBatch response type. message MsgDepositWithinBatchResponse {} -// `MsgWithdrawWithinBatch` defines an `sdk.Msg` type that supports submitting +// `MsgWithdrawWithinBatch` defines an `sdk.Msg` type that supports submitting // a withdraw request to the batch of the liquidity pool. -// Withdraw is submitted to the batch from the Liquidity pool with the +// Withdraw is submitted to the batch from the Liquidity pool with the // specified `pool_id`, `pool_coin` of the pool. -// This request is stacked in the batch of the liquidity pool, is not processed +// This request is stacked in the batch of the liquidity pool, is not processed // immediately, and is processed in the `endblock` at the same time as other requests. // // See: https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md message MsgWithdrawWithinBatch { - option (gogoproto.equal) = false; + option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; - string withdrawer_address = 1 [ (gogoproto.moretags) = "yaml:\"withdrawer_address\"", + string withdrawer_address = 1 [ + (gogoproto.moretags) = "yaml:\"withdrawer_address\"", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "account address of the origin of this message", example: "\"cosmos1e35y69rhrt7y4yce5l5u73sjnxu0l33wvznyun\"", format: "sdk.AccAddress" - }]; + } + ]; // id of the target pool - uint64 pool_id = 2 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", + uint64 pool_id = 2 [ + (gogoproto.moretags) = "yaml:\"pool_id\"", + (gogoproto.jsontag) = "pool_id", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"1\"", format: "uint64" - }]; + } + ]; cosmos.base.v1beta1.Coin pool_coin = 3 [ (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"pool_coin\"", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "{\"denom\": \"poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4\", \"amount\": \"1000\"}", format: "sdk.Coin" - }]; + } + ]; } // MsgWithdrawWithinBatchResponse defines the Msg/WithdrawWithinBatch response type. @@ -138,7 +154,7 @@ message MsgWithdrawWithinBatchResponse {} // Submit swap offer to the liquidity pool batch with the specified the `pool_id`, `swap_type_id`, // `demand_coin_denom` with the coin and the price you're offering // and `offer_coin_fee` must be half of offer coin amount * current `params.swap_fee_rate` and ceil for reservation to pay fees. -// This request is stacked in the batch of the liquidity pool, is not processed +// This request is stacked in the batch of the liquidity pool, is not processed // immediately, and is processed in the `endblock` at the same time as other requests. // You must request the same fields as the pool. // Only the default `swap_type_id` 1 is supported. @@ -146,65 +162,74 @@ message MsgWithdrawWithinBatchResponse {} // See: https://github.com/cosmos/gaia/v9/tree/develop/doc // https://github.com/cosmos/gaia/v9/blob/develop/x/liquidity/spec/04_messages.md message MsgSwapWithinBatch { - option (gogoproto.equal) = false; + option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; // address of swap requester - string swap_requester_address = 1 [(gogoproto.moretags) = "yaml:\"swap_requester_address\"", + string swap_requester_address = 1 [ + (gogoproto.moretags) = "yaml:\"swap_requester_address\"", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "account address of the origin of this message", example: "\"cosmos1e35y69rhrt7y4yce5l5u73sjnxu0l33wvznyun\"", format: "sdk.AccAddress" - }]; + } + ]; // id of swap type, must match the value in the pool. Only `swap_type_id` 1 is supported. - uint64 pool_id = 2 [(gogoproto.moretags) = "yaml:\"pool_id\"", (gogoproto.jsontag) = "pool_id", + uint64 pool_id = 2 [ + (gogoproto.moretags) = "yaml:\"pool_id\"", + (gogoproto.jsontag) = "pool_id", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"1\"", format: "uint64" - }]; + } + ]; // id of swap type. Must match the value in the pool. - uint32 swap_type_id = 3 [(gogoproto.moretags) = "yaml:\"swap_type_id\"", + uint32 swap_type_id = 3 [ + (gogoproto.moretags) = "yaml:\"swap_type_id\"", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"1\"", format: "uint32" - }]; + } + ]; // offer sdk.coin for the swap request, must match the denom in the pool. cosmos.base.v1beta1.Coin offer_coin = 4 [ - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"offer_coin\"", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"offer_coin\"", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "{\"denom\": \"denomX\", \"amount\": \"1000000\"}", format: "sdk.Coin" - }]; + } + ]; // denom of demand coin to be exchanged on the swap request, must match the denom in the pool. - string demand_coin_denom = 5 [(gogoproto.moretags) = "yaml:\"demand_coin_denom\"", - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"denomB\"", - }]; + string demand_coin_denom = 5 [ + (gogoproto.moretags) = "yaml:\"demand_coin_denom\"", + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "\"denomB\""} + ]; // half of offer coin amount * params.swap_fee_rate and ceil for reservation to pay fees. cosmos.base.v1beta1.Coin offer_coin_fee = 6 [ - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"offer_coin_fee\"", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"offer_coin_fee\"", (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "{\"denom\": \"denomX\", \"amount\": \"5000\"}", format: "sdk.Coin" - } + } ]; // limit order price for the order, the price is the exchange ratio of X/Y - // where X is the amount of the first coin and Y is the amount - // of the second coin when their denoms are sorted alphabetically. + // where X is the amount of the first coin and Y is the amount + // of the second coin when their denoms are sorted alphabetically. string order_price = 7 [ - (gogoproto.moretags) = "yaml:\"order_price\"", + (gogoproto.moretags) = "yaml:\"order_price\"", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false, + (gogoproto.nullable) = false, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"1.1\"", format: "sdk.Dec" - }]; + } + ]; } // MsgSwapWithinBatchResponse defines the Msg/Swap response type. diff --git a/third_party/proto/cosmos_proto/coin.proto b/third_party/proto/cosmos_proto/coin.proto deleted file mode 100644 index fab75284b7f..00000000000 --- a/third_party/proto/cosmos_proto/coin.proto +++ /dev/null @@ -1,40 +0,0 @@ -syntax = "proto3"; -package cosmos.base.v1beta1; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/cosmos/cosmos-sdk/types"; -option (gogoproto.goproto_stringer_all) = false; -option (gogoproto.stringer_all) = false; - -// 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. -message Coin { - option (gogoproto.equal) = true; - - string denom = 1; - string amount = 2 [(gogoproto.customtype) = "Int", (gogoproto.nullable) = false]; -} - -// 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. -message DecCoin { - option (gogoproto.equal) = true; - - string denom = 1; - string amount = 2 [(gogoproto.customtype) = "Dec", (gogoproto.nullable) = false]; -} - -// IntProto defines a Protobuf wrapper around an Int object. -message IntProto { - string int = 1 [(gogoproto.customtype) = "Int", (gogoproto.nullable) = false]; -} - -// DecProto defines a Protobuf wrapper around a Dec object. -message DecProto { - string dec = 1 [(gogoproto.customtype) = "Dec", (gogoproto.nullable) = false]; -} diff --git a/third_party/proto/cosmos_proto/cosmos.proto b/third_party/proto/cosmos_proto/cosmos.proto deleted file mode 100644 index 167b170757b..00000000000 --- a/third_party/proto/cosmos_proto/cosmos.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; -package cosmos_proto; - -import "google/protobuf/descriptor.proto"; - -option go_package = "github.com/regen-network/cosmos-proto"; - -extend google.protobuf.MessageOptions { - string interface_type = 93001; - - string implements_interface = 93002; -} - -extend google.protobuf.FieldOptions { - string accepts_interface = 93001; -} diff --git a/x/globalfee/types/genesis.pb.go b/x/globalfee/types/genesis.pb.go index 914b77f1ed6..029b03ec88f 100644 --- a/x/globalfee/types/genesis.pb.go +++ b/x/globalfee/types/genesis.pb.go @@ -132,27 +132,27 @@ func init() { var fileDescriptor_015b3e8b7a7c65c5 = []byte{ // 325 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x31, 0x4b, 0x03, 0x31, - 0x14, 0xc7, 0x2f, 0x08, 0x1d, 0xae, 0x0e, 0xe5, 0x10, 0xa9, 0xa5, 0xe4, 0xe4, 0x70, 0x28, 0xa8, - 0x09, 0xad, 0x9b, 0xe3, 0x29, 0x74, 0x2d, 0x75, 0x73, 0xa9, 0xb9, 0x33, 0xc6, 0x60, 0x73, 0x09, - 0x4d, 0x2a, 0xf6, 0x5b, 0xf8, 0x39, 0xfc, 0x0c, 0xee, 0x76, 0xec, 0xe8, 0x54, 0xe5, 0x6e, 0x73, - 0xf4, 0x13, 0xc8, 0x25, 0x67, 0x2b, 0x9c, 0x53, 0x02, 0xef, 0xf7, 0x7e, 0xff, 0xc7, 0x7b, 0xfe, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xc1, 0x4a, 0xc3, 0x30, + 0x18, 0xc7, 0x1b, 0x84, 0x1d, 0x3a, 0x0f, 0xa3, 0x88, 0xcc, 0x31, 0x52, 0x29, 0x1e, 0x06, 0x6a, + 0xc2, 0xe6, 0xcd, 0x63, 0x15, 0x76, 0x1d, 0xf3, 0xe6, 0x65, 0xa6, 0x35, 0xc6, 0xe0, 0xd2, 0x84, + 0x25, 0x13, 0xf7, 0x16, 0x3e, 0x87, 0xcf, 0xe0, 0xdd, 0x1d, 0x77, 0xf4, 0x34, 0xa5, 0xbd, 0x79, + 0xf4, 0x09, 0xa4, 0x49, 0xdd, 0x84, 0x7a, 0x6a, 0x28, 0xff, 0xff, 0xef, 0xc7, 0xf7, 0x7d, 0xfe, 0x11, 0x23, 0x9c, 0x60, 0x36, 0x95, 0x09, 0x99, 0xde, 0x51, 0x8a, 0x1f, 0xfb, 0x09, 0x35, 0xa4, - 0x8f, 0x19, 0xcd, 0xa8, 0xe6, 0x1a, 0xa9, 0x99, 0x34, 0x32, 0xd8, 0x2f, 0x29, 0xb4, 0xa1, 0x50, - 0x45, 0x75, 0xf6, 0x98, 0x64, 0xd2, 0x22, 0xb8, 0xfc, 0x39, 0xba, 0x03, 0x53, 0xa9, 0x85, 0xd4, - 0x38, 0x21, 0x7a, 0x2b, 0x4c, 0x25, 0xcf, 0x5c, 0x3d, 0xba, 0xf1, 0x77, 0x87, 0x4e, 0x7f, 0x65, - 0x88, 0xa1, 0xc1, 0xc8, 0x6f, 0x28, 0x32, 0x23, 0x42, 0xb7, 0xc1, 0x21, 0xe8, 0x35, 0x07, 0x10, - 0xfd, 0x1f, 0x87, 0x46, 0x96, 0x8a, 0xdb, 0xcb, 0x75, 0xe8, 0x7d, 0xad, 0xc3, 0x96, 0xeb, 0x3a, - 0x91, 0x82, 0x1b, 0x2a, 0x94, 0x59, 0x8c, 0x2b, 0x4f, 0xf4, 0x06, 0xfc, 0x86, 0x83, 0x83, 0x57, - 0xe0, 0x07, 0x82, 0x67, 0x5c, 0xcc, 0xc5, 0x84, 0x11, 0x3d, 0x51, 0x33, 0x9e, 0xd2, 0x32, 0x69, - 0xa7, 0xd7, 0x1c, 0x74, 0x91, 0x1b, 0x15, 0x95, 0xa3, 0x6e, 0x62, 0x2e, 0x69, 0x7a, 0x21, 0x79, - 0x16, 0xab, 0x2a, 0xa7, 0x5b, 0xef, 0xdf, 0x66, 0x7e, 0xaf, 0xc3, 0x83, 0x05, 0x11, 0xd3, 0xf3, - 0xa8, 0x4e, 0x45, 0x2f, 0x1f, 0xe1, 0x31, 0xe3, 0xe6, 0x7e, 0x9e, 0xa0, 0x54, 0x0a, 0x5c, 0xed, - 0xc5, 0x3d, 0xa7, 0xfa, 0xf6, 0x01, 0x9b, 0x85, 0xa2, 0xfa, 0x37, 0x50, 0x8f, 0x5b, 0x95, 0x63, - 0x48, 0xf4, 0xc8, 0x1a, 0xe2, 0x78, 0x99, 0x43, 0xb0, 0xca, 0x21, 0xf8, 0xcc, 0x21, 0x78, 0x2e, - 0xa0, 0xb7, 0x2a, 0xa0, 0xf7, 0x5e, 0x40, 0xef, 0xba, 0x57, 0x17, 0xdb, 0x5b, 0x3e, 0xfd, 0xb9, - 0xa6, 0xd5, 0x27, 0x0d, 0xbb, 0xf6, 0xb3, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x48, 0x6d, 0x01, - 0xcd, 0xec, 0x01, 0x00, 0x00, + 0x8f, 0x19, 0xcd, 0xa8, 0xe6, 0x1a, 0xa9, 0x99, 0x34, 0x32, 0xd8, 0x2f, 0x53, 0x68, 0x93, 0x42, + 0x55, 0xaa, 0x03, 0x53, 0xa9, 0x85, 0xd4, 0x38, 0x21, 0x7a, 0x5b, 0x4d, 0x25, 0xcf, 0x5c, 0xaf, + 0xb3, 0xc7, 0x24, 0x93, 0xf6, 0x89, 0xcb, 0x97, 0xfb, 0x1b, 0xdd, 0xf8, 0xbb, 0x43, 0x87, 0xbf, + 0x32, 0xc4, 0xd0, 0x60, 0xe4, 0x37, 0x14, 0x99, 0x11, 0xa1, 0xdb, 0xe0, 0x10, 0xf4, 0x9a, 0x03, + 0x88, 0xfe, 0xd7, 0xa1, 0x91, 0x4d, 0xc5, 0xed, 0xe5, 0x3a, 0xf4, 0xbe, 0xd6, 0x61, 0xcb, 0xb5, + 0x4e, 0xa4, 0xe0, 0x86, 0x0a, 0x65, 0x16, 0xe3, 0x8a, 0x13, 0xbd, 0x01, 0xbf, 0xe1, 0xc2, 0xc1, + 0x2b, 0xf0, 0x03, 0xc1, 0x33, 0x2e, 0xe6, 0x62, 0xc2, 0x88, 0x9e, 0xa8, 0x19, 0x4f, 0x69, 0x69, + 0xda, 0xe9, 0x35, 0x07, 0x5d, 0xe4, 0x06, 0x40, 0xe5, 0x00, 0x1b, 0xcd, 0x25, 0x4d, 0x2f, 0x24, + 0xcf, 0x62, 0x55, 0x79, 0xba, 0xf5, 0xfe, 0xd6, 0xf9, 0xbd, 0x0e, 0x0f, 0x16, 0x44, 0x4c, 0xcf, + 0xa3, 0x7a, 0x2a, 0x7a, 0xf9, 0x08, 0x8f, 0x19, 0x37, 0xf7, 0xf3, 0x04, 0xa5, 0x52, 0xe0, 0x6a, + 0x5b, 0xee, 0x73, 0xaa, 0x6f, 0x1f, 0xb0, 0x59, 0x28, 0xaa, 0x7f, 0x85, 0x7a, 0xdc, 0xaa, 0x18, + 0x43, 0xa2, 0x47, 0x96, 0x10, 0xc7, 0xcb, 0x1c, 0x82, 0x55, 0x0e, 0xc1, 0x67, 0x0e, 0xc1, 0x73, + 0x01, 0xbd, 0x55, 0x01, 0xbd, 0xf7, 0x02, 0x7a, 0xd7, 0xbd, 0x3a, 0xd8, 0xde, 0xf2, 0xe9, 0xcf, + 0x35, 0x2d, 0x3e, 0x69, 0xd8, 0xb5, 0x9f, 0xfd, 0x04, 0x00, 0x00, 0xff, 0xff, 0x89, 0x2c, 0xa8, + 0xb0, 0xec, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/x/globalfee/types/query.pb.go b/x/globalfee/types/query.pb.go index 94848fc4729..3a69d1e0a33 100644 --- a/x/globalfee/types/query.pb.go +++ b/x/globalfee/types/query.pb.go @@ -125,31 +125,31 @@ func init() { } var fileDescriptor_12a736cede25d10a = []byte{ - // 377 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xb1, 0x4f, 0xdb, 0x40, - 0x14, 0xc6, 0x7d, 0xad, 0xda, 0xc1, 0x5d, 0x22, 0xab, 0xaa, 0xda, 0xc8, 0x3d, 0x57, 0x9e, 0xa2, - 0x36, 0xbd, 0x53, 0xd2, 0x76, 0xe9, 0x98, 0x56, 0x62, 0x42, 0x82, 0x8c, 0x2c, 0xd1, 0xd9, 0x1c, - 0xc7, 0x09, 0x9f, 0x9f, 0x93, 0x3b, 0x23, 0xbc, 0xf2, 0x17, 0x20, 0xf1, 0x5f, 0xb0, 0xb2, 0xc2, - 0x9e, 0x31, 0x12, 0x0b, 0x93, 0x41, 0x09, 0x13, 0x23, 0x7f, 0x01, 0xb2, 0x9d, 0x00, 0x8a, 0x09, - 0x12, 0x93, 0x2d, 0x7d, 0xbf, 0xf7, 0x3e, 0x7d, 0xdf, 0x3d, 0xdb, 0x17, 0x4c, 0x32, 0x2a, 0x22, - 0x08, 0x58, 0xb4, 0xc3, 0x39, 0xdd, 0xef, 0x04, 0xdc, 0xb0, 0x0e, 0x1d, 0xa6, 0x7c, 0x94, 0x91, - 0x64, 0x04, 0x06, 0x9c, 0x4f, 0x05, 0x43, 0x1e, 0x18, 0x32, 0x67, 0x9a, 0x1f, 0x05, 0x08, 0x28, - 0x11, 0x5a, 0xfc, 0x55, 0x74, 0xd3, 0x15, 0x00, 0x22, 0xe2, 0x94, 0x25, 0x92, 0xb2, 0x38, 0x06, - 0xc3, 0x8c, 0x84, 0x58, 0xcf, 0x55, 0x1c, 0x82, 0x56, 0xa0, 0x69, 0xc0, 0xf4, 0xa3, 0x59, 0x08, - 0x32, 0xae, 0x74, 0x1f, 0xdb, 0xee, 0x66, 0x61, 0xbd, 0x2e, 0x63, 0xa9, 0x52, 0xb5, 0xc6, 0xf4, - 0xc6, 0x48, 0x86, 0x5c, 0xf7, 0xf9, 0x30, 0xe5, 0xda, 0xf8, 0x39, 0xb2, 0xbf, 0xae, 0x00, 0x74, - 0x02, 0xb1, 0xe6, 0xce, 0x19, 0xb2, 0x1d, 0x55, 0x89, 0x03, 0xc1, 0xf4, 0x20, 0x29, 0xe5, 0xcf, - 0xe8, 0xdb, 0xdb, 0xd6, 0x87, 0xae, 0x4b, 0x2a, 0x7f, 0x52, 0xf8, 0x2f, 0x82, 0x90, 0xff, 0x3c, - 0xfc, 0x07, 0x32, 0xee, 0x25, 0xe3, 0xdc, 0xb3, 0x6e, 0x73, 0xcf, 0xad, 0xcf, 0xb7, 0x41, 0x49, - 0xc3, 0x55, 0x62, 0xb2, 0xbb, 0xdc, 0xfb, 0x92, 0x31, 0x15, 0xfd, 0xf5, 0xeb, 0x94, 0x7f, 0x72, - 0xe5, 0xfd, 0x10, 0xd2, 0xec, 0xa6, 0x01, 0x09, 0x41, 0xd1, 0x79, 0xd8, 0xea, 0xf3, 0x53, 0x6f, - 0xef, 0x51, 0x93, 0x25, 0x5c, 0x2f, 0x0c, 0x75, 0xbf, 0xa1, 0x96, 0x62, 0x74, 0xcf, 0x91, 0xfd, - 0xae, 0x0c, 0xe8, 0x9c, 0x22, 0xbb, 0xb1, 0x9c, 0xd2, 0xf9, 0x4d, 0x9e, 0x7f, 0x0c, 0xf2, 0x52, - 0x6b, 0xcd, 0x3f, 0xaf, 0x9c, 0xaa, 0xaa, 0xf4, 0xbb, 0x87, 0x17, 0x37, 0xc7, 0x6f, 0xda, 0xce, - 0x77, 0xba, 0xe2, 0x4a, 0xea, 0x0d, 0xf4, 0x7a, 0xe3, 0x29, 0x46, 0x93, 0x29, 0x46, 0xd7, 0x53, - 0x8c, 0x8e, 0x66, 0xd8, 0x9a, 0xcc, 0xb0, 0x75, 0x39, 0xc3, 0xd6, 0x56, 0xab, 0x5e, 0x4c, 0xb9, - 0xf6, 0xe0, 0xc9, 0xe2, 0xb2, 0x9e, 0xe0, 0x7d, 0x79, 0x0b, 0xbf, 0xee, 0x03, 0x00, 0x00, 0xff, - 0xff, 0x73, 0x0d, 0xf8, 0x43, 0x9d, 0x02, 0x00, 0x00, + // 378 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x52, 0x31, 0x4f, 0xdb, 0x40, + 0x14, 0xf6, 0xb5, 0x6a, 0x07, 0x77, 0x89, 0xac, 0xaa, 0x6a, 0x23, 0xf7, 0x5c, 0x79, 0x8a, 0xda, + 0xf4, 0x4e, 0x49, 0xdb, 0xa5, 0x63, 0x5a, 0x89, 0x09, 0x09, 0x32, 0xb2, 0x44, 0x67, 0x73, 0x1c, + 0x27, 0x7c, 0x7e, 0x4e, 0xee, 0x8c, 0xf0, 0xca, 0x2f, 0x40, 0xe2, 0x5f, 0xb0, 0xb2, 0xc2, 0x9e, + 0x31, 0x12, 0x0b, 0x93, 0x41, 0x09, 0x13, 0x23, 0xbf, 0x00, 0xd9, 0x4e, 0x00, 0xc5, 0x04, 0x89, + 0xc9, 0x4f, 0xfe, 0xbe, 0xef, 0xbd, 0xf7, 0x7d, 0xf7, 0x6c, 0x5f, 0x30, 0xc9, 0xa8, 0x88, 0x20, + 0x60, 0xd1, 0x0e, 0xe7, 0x74, 0xbf, 0x13, 0x70, 0xc3, 0x3a, 0x74, 0x98, 0xf2, 0x51, 0x46, 0x92, + 0x11, 0x18, 0x70, 0x3e, 0x15, 0x1c, 0xf2, 0xc0, 0x21, 0x73, 0x4e, 0x13, 0x87, 0xa0, 0x15, 0x68, + 0x1a, 0x30, 0xfd, 0x28, 0x0c, 0x41, 0xc6, 0x95, 0xae, 0xf9, 0x51, 0x80, 0x80, 0xb2, 0xa4, 0x45, + 0x35, 0xff, 0xeb, 0x0a, 0x00, 0x11, 0x71, 0xca, 0x12, 0x49, 0x59, 0x1c, 0x83, 0x61, 0x46, 0x42, + 0xac, 0x2b, 0xd4, 0xc7, 0xb6, 0xbb, 0x59, 0x8c, 0x5e, 0x97, 0xb1, 0x54, 0xa9, 0x5a, 0x63, 0x7a, + 0x63, 0x24, 0x43, 0xae, 0xfb, 0x7c, 0x98, 0x72, 0x6d, 0xfc, 0x1c, 0xd9, 0x5f, 0x57, 0x10, 0x74, + 0x02, 0xb1, 0xe6, 0xce, 0x19, 0xb2, 0x1d, 0x55, 0x81, 0x03, 0xc1, 0xf4, 0x20, 0x29, 0xe1, 0xcf, + 0xe8, 0xdb, 0xdb, 0xd6, 0x87, 0xae, 0x4b, 0xaa, 0x9d, 0x49, 0xb1, 0xf3, 0xc2, 0x08, 0xf9, 0xcf, + 0xc3, 0x7f, 0x20, 0xe3, 0x5e, 0x32, 0xce, 0x3d, 0xeb, 0x36, 0xf7, 0xdc, 0xba, 0xbe, 0x0d, 0x4a, + 0x1a, 0xae, 0x12, 0x93, 0xdd, 0xe5, 0xde, 0x97, 0x8c, 0xa9, 0xe8, 0xaf, 0x5f, 0x67, 0xf9, 0x27, + 0x57, 0xde, 0x0f, 0x21, 0xcd, 0x6e, 0x1a, 0x90, 0x10, 0x14, 0x9d, 0x07, 0x54, 0x7d, 0x7e, 0xea, + 0xed, 0x3d, 0x6a, 0xb2, 0x84, 0xeb, 0xc5, 0x40, 0xdd, 0x6f, 0xa8, 0x25, 0x1b, 0xdd, 0x73, 0x64, + 0xbf, 0x2b, 0x0d, 0x3a, 0xa7, 0xc8, 0x6e, 0x2c, 0xbb, 0x74, 0x7e, 0x93, 0xe7, 0x1f, 0x83, 0xbc, + 0x94, 0x5a, 0xf3, 0xcf, 0x2b, 0x55, 0x55, 0x94, 0x7e, 0xf7, 0xf0, 0xe2, 0xe6, 0xf8, 0x4d, 0xdb, + 0xf9, 0x4e, 0x57, 0x5c, 0x49, 0x3d, 0x81, 0x5e, 0x6f, 0x3c, 0xc5, 0x68, 0x32, 0xc5, 0xe8, 0x7a, + 0x8a, 0xd1, 0xd1, 0x0c, 0x5b, 0x93, 0x19, 0xb6, 0x2e, 0x67, 0xd8, 0xda, 0x6a, 0xd5, 0x83, 0x29, + 0xdb, 0x1e, 0x3c, 0x69, 0x5c, 0xc6, 0x13, 0xbc, 0x2f, 0x6f, 0xe1, 0xd7, 0x7d, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xdc, 0xad, 0x21, 0xef, 0x9d, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. From 2c210747a90329eba3284cb1c69535f25d7e89cc Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Wed, 10 May 2023 15:52:06 +0000 Subject: [PATCH 24/24] return the version of go to 1.20 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 96020d53909..c48af9f252b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/cosmos/gaia/v9 -go 1.19 +go 1.20 require ( cosmossdk.io/math v1.0.0