Skip to content

Commit

Permalink
feat: include flag versioned in query markets to allow to query disab…
Browse files Browse the repository at this point in the history
…led markets (#1585)

* make market inmutable and include market version

* temp commit after adding market version

* make test pass

* add genesis part

* create changelog

* add option for market creation when another one is closed

* make tests pass

* make linter

* fix bug

* add convenience method for saving market

* add new methods

* remove comments

* add query versioned markets

* update query markets

* update changelog

* docs(perp): small docs improvements for CLI and proto comment

---------

Co-authored-by: Unique-Divine <[email protected]>
  • Loading branch information
jgimeno and Unique-Divine authored Sep 19, 2023
1 parent cdf86c5 commit a472744
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 124 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#1503](https://github.com/NibiruChain/nibiru/pull/1503) - feat(wasm): add Oracle Exchange Rate query for wasm
* [#1543](https://github.com/NibiruChain/nibiru/pull/1543) - epic(devgas): devgas module for incentivizing smart contract
* [#1559](https://github.com/NibiruChain/nibiru/pull/1559) - feat: add versions to markets to allow to disable them
* [#1585](https://github.com/NibiruChain/nibiru/pull/1585) - feat: include flag versioned in query markets to allow to query disabled markets

### Bug Fixes

Expand Down Expand Up @@ -649,4 +650,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Testing

* [#695](https://github.com/NibiruChain/nibiru/pull/695) Add `OpenPosition` integration tests.
* [#692](https://github.com/NibiruChain/nibiru/pull/692) Add test coverage for Perp MsgServer methods.
* [#692](https://github.com/NibiruChain/nibiru/pull/692) Add test coverage for Perp MsgServer methods.
12 changes: 8 additions & 4 deletions proto/nibiru/perp/v2/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import "nibiru/perp/v2/state.proto";
option go_package = "github.com/NibiruChain/nibiru/x/perp/v2/types";

// GenesisState defines the perp module's genesis state.
// Thge genesis state is used not only to start the network but also useful for
// exporting and importing state during network upgrades.
message GenesisState {
repeated Market markets = 2 [ (gogoproto.nullable) = false ];

repeated GenesisMarketLastVersion market_last_versions = 8 [ (gogoproto.nullable) = false ];

repeated AMM amms = 3 [ (gogoproto.nullable) = false ];

repeated Position positions = 4 [ (gogoproto.nullable) = false ];
Expand All @@ -34,9 +34,13 @@ message GenesisState {
(gogoproto.nullable) = false
];
}

repeated GenesisMarketLastVersion market_last_versions = 8
[ (gogoproto.nullable) = false ];
}

// GenesisMarketLastVersion is the last version including pair only used for genesis
// GenesisMarketLastVersion is the last version including pair only used for
// genesis
message GenesisMarketLastVersion {
string pair = 1 [
(gogoproto.customtype) =
Expand All @@ -45,4 +49,4 @@ message GenesisMarketLastVersion {
];

uint64 version = 2;
}
}
4 changes: 3 additions & 1 deletion proto/nibiru/perp/v2/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ message AmmMarket {
AMM amm = 2 [ (gogoproto.nullable) = false ];
}

message QueryMarketsRequest {}
message QueryMarketsRequest {
bool versioned = 1;
}

message QueryMarketsResponse {
repeated AmmMarket amm_markets = 1 [ (gogoproto.nullable) = false ];
Expand Down
91 changes: 91 additions & 0 deletions proto/nibiru/tokenfactory/v1/state.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
syntax = "proto3";

package nibiru.tokenfactory.v1;

import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/NibiruChain/nibiru/x/tokenfactory/types";

// DenomAuthorityMetadata specifies metadata foraddresses that have specific
// capabilities over a token factory denom. Right now there is only one Admin
// permission, but is planned to be extended to the future.
message DenomAuthorityMetadata {
option (gogoproto.equal) = true;

// Admin: Bech32 address of the admin for the tokefactory denom. Can be empty
// for no admin.
string admin = 1 [ (gogoproto.moretags) = "yaml:\"admin\"" ];
}

// ModuleParams defines the parameters for the tokenfactory module.
//
// ### On Denom Creation Costs
//
// We'd like for fees to be paid by the user/signer of a ransaction, but in many
// casess, token creation is abstracted away behind a smart contract. Setting a
// nonzero `denom_creation_fee` would force each contract to handle collecting
// and paying a fees for denom (factory/{contract-addr}/{subdenom}) creation on
// behalf of the end user.
//
// For IBC token transfers, it's unclear who should pay the fee—the contract,
// the relayer, or the original sender?
// > "Charging fees will mess up composability, the same way Terra transfer tax
// caused all kinds of headaches for contract devs." - @ethanfrey
//
// ### Recommended Solution
//
// Have the end user (signer) pay fees directly in the form of higher gas costs.
// This way, contracts won't need to handle collecting or paying fees. And for
// IBC, the gas costs are already paid by the original sender and can be
// estimated by the relayer. It's easier to tune gas costs to make spam
// prohibitively expensive since there are per-transaction and per-block gas
// limits.
//
// See https://github.com/CosmWasm/token-factory/issues/11 for the initial
// discussion of the issue with @ethanfrey and @valardragon.
message ModuleParams {
// Adds gas consumption to the execution of `MsgCreateDenom` as a method of
// spam prevention. Defaults to 10 NIBI.
uint64 denom_creation_gas_consume = 1
[ (gogoproto.moretags) = "yaml:\"denom_creation_gas_consume\"" ];
}

// TFDenom is a token factory (TF) denom. The canonical representation is
// "tf/{creator}/{subdenom}", its unique denomination in the x/bank module.
message TFDenom {
option (gogoproto.goproto_stringer) = false;
option (gogoproto.stringer) = false;

// Creator: Bech32 address of the creator of the denom.
string creator = 1;
// Subdenom: Unique suffix of a token factory denom. A subdenom is specific
// to a given creator. It is the name given during a token factory "Mint".
string subdenom = 2;
}

// ----------------------------------------------
// Genesis
// ----------------------------------------------

// GenesisState for the Token Factory module.
message GenesisState {
ModuleParams params = 1 [ (gogoproto.nullable) = false ];

repeated GenesisDenom factory_denoms = 2 [
(gogoproto.moretags) = "yaml:\"factory_denoms\"",
(gogoproto.nullable) = false
];
}

// GenesisDenom defines a tokenfactory denoms in the genesis state.
message GenesisDenom {
option (gogoproto.equal) = true;

string denom = 1 [ (gogoproto.moretags) = "yaml:\"denom\"" ];
DenomAuthorityMetadata authority_metadata = 2 [
(gogoproto.moretags) = "yaml:\"authority_metadata\"",
(gogoproto.nullable) = false
];
}
21 changes: 18 additions & 3 deletions x/perp/v2/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
types "github.com/NibiruChain/nibiru/x/perp/v2/types"
)

const FlagVersioned = "versioned"

// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd() *cobra.Command {
// Group stablecoin queries under a subcommand
Expand Down Expand Up @@ -146,8 +148,12 @@ func CmdQueryModuleAccounts() *cobra.Command {
func CmdQueryMarkets() *cobra.Command {
cmd := &cobra.Command{
Use: "markets",
Short: "query all market info",
Args: cobra.NoArgs,
Short: "Query all market info",
Long: `
Query all market info. By default, only active tradable markets are shown.
If --versioned is to to true, the query will return all markets including the
inactive ones.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
Expand All @@ -156,7 +162,14 @@ func CmdQueryMarkets() *cobra.Command {

queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.QueryMarkets(cmd.Context(), &types.QueryMarketsRequest{})
versioned, err := cmd.Flags().GetBool(FlagVersioned)
if err != nil {
return err
}

res, err := queryClient.QueryMarkets(cmd.Context(), &types.QueryMarketsRequest{
Versioned: versioned,
})
if err != nil {
return err
}
Expand All @@ -165,6 +178,8 @@ func CmdQueryMarkets() *cobra.Command {
},
}

cmd.Flags().Bool(FlagVersioned, false, "toggles whether to include inactive markets")

flags.AddQueryFlagsToCmd(cmd)

return cmd
Expand Down
31 changes: 22 additions & 9 deletions x/perp/v2/integration/action/market.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (c createMarketAction) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context
}

// CreateCustomMarket creates a market with custom parameters
func CreateCustomMarket(pair asset.Pair, marketModifiers ...marketModifier) action.Action {
func CreateCustomMarket(pair asset.Pair, marketModifiers ...MarketModifier) action.Action {
market := types.DefaultMarket(pair)
amm := types.AMM{
Pair: pair,
Expand All @@ -75,52 +75,65 @@ func CreateCustomMarket(pair asset.Pair, marketModifiers ...marketModifier) acti
}
}

type marketModifier func(market *types.Market, amm *types.AMM)
type MarketModifier func(market *types.Market, amm *types.AMM)

func WithPrepaidBadDebt(amount sdkmath.Int) marketModifier {
func WithPrepaidBadDebt(amount sdkmath.Int) MarketModifier {
return func(market *types.Market, amm *types.AMM) {
market.PrepaidBadDebt = sdk.NewCoin(market.Pair.QuoteDenom(), amount)
}
}

func WithPricePeg(newValue sdk.Dec) marketModifier {
func WithPricePeg(newValue sdk.Dec) MarketModifier {
return func(market *types.Market, amm *types.AMM) {
amm.PriceMultiplier = newValue
}
}

func WithTotalLong(amount sdk.Dec) marketModifier {
func WithTotalLong(amount sdk.Dec) MarketModifier {
return func(market *types.Market, amm *types.AMM) {
amm.TotalLong = amount
}
}

func WithTotalShort(amount sdk.Dec) marketModifier {
func WithTotalShort(amount sdk.Dec) MarketModifier {
return func(market *types.Market, amm *types.AMM) {
amm.TotalShort = amount
}
}

func WithSqrtDepth(amount sdk.Dec) marketModifier {
func WithSqrtDepth(amount sdk.Dec) MarketModifier {
return func(market *types.Market, amm *types.AMM) {
amm.SqrtDepth = amount
amm.BaseReserve = amount
amm.QuoteReserve = amount
}
}

func WithLatestMarketCPF(amount sdk.Dec) marketModifier {
func WithLatestMarketCPF(amount sdk.Dec) MarketModifier {
return func(market *types.Market, amm *types.AMM) {
market.LatestCumulativePremiumFraction = amount
}
}

func WithMaxFundingRate(amount sdk.Dec) marketModifier {
func WithMaxFundingRate(amount sdk.Dec) MarketModifier {
return func(market *types.Market, amm *types.AMM) {
market.MaxFundingRate = amount
}
}

func WithVersion(version uint64) MarketModifier {
return func(market *types.Market, amm *types.AMM) {
market.Version = version
amm.Version = version
}
}

func WithEnabled(enabled bool) MarketModifier {
return func(market *types.Market, amm *types.AMM) {
market.Enabled = enabled
}
}

type editPriceMultiplier struct {
pair asset.Pair
newValue sdk.Dec
Expand Down
25 changes: 22 additions & 3 deletions x/perp/v2/integration/action/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ func (q queryPositionNotFound) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Cont
Trader: q.traderAddress.String(),
})
if !errors.Is(err, collections.ErrNotFound) {
return ctx, fmt.Errorf("expected position not found, but found a position for pair %s, trader %s", q.pair, q.traderAddress), false
return ctx, fmt.Errorf(
"expected position not found, but found a position for pair %s, trader %s",
q.pair,
q.traderAddress,
), false
}

return ctx, nil, false
Expand All @@ -145,13 +149,16 @@ func QueryPositionNotFound(pair asset.Pair, traderAddress sdk.AccAddress) action
}

type queryMarkets struct {
versioned bool
allResponseCheckers []QueryMarketsChecker
}

func (q queryMarkets) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
queryServer := keeper.NewQuerier(app.PerpKeeperV2)

resp, err := queryServer.QueryMarkets(sdk.WrapSDKContext(ctx), &types.QueryMarketsRequest{})
resp, err := queryServer.QueryMarkets(sdk.WrapSDKContext(ctx), &types.QueryMarketsRequest{
Versioned: q.versioned,
})
if err != nil {
return ctx, err, false
}
Expand All @@ -165,8 +172,10 @@ func (q queryMarkets) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, erro
return ctx, nil, false
}

func QueryMarkets(responseCheckers ...QueryMarketsChecker) action.Action {
// QueryMarkets queries all markets, versioned contains active and inactive markets
func QueryMarkets(versioned bool, responseCheckers ...QueryMarketsChecker) action.Action {
return queryMarkets{
versioned: versioned,
allResponseCheckers: responseCheckers,
}
}
Expand All @@ -188,6 +197,16 @@ func QueryMarkets_MarketsShouldContain(expectedMarket types.Market) QueryMarkets
}
}

func QueryMarkets_ShouldLength(length int) QueryMarketsChecker {
return func(resp []types.AmmMarket) error {
if len(resp) != length {
return fmt.Errorf("expected markets to have length %d, got %d", length, len(resp))
}

return nil
}
}

type queryModuleAccounts struct {
allResponseCheckers []QueryModuleAccountsChecker
}
Expand Down
4 changes: 2 additions & 2 deletions x/perp/v2/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,15 @@ func (q queryServer) ModuleAccounts(
}

func (q queryServer) QueryMarkets(
goCtx context.Context, _ *types.QueryMarketsRequest,
goCtx context.Context, req *types.QueryMarketsRequest,
) (*types.QueryMarketsResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

var ammMarkets []types.AmmMarket
markets := q.k.Markets.Iterate(ctx, collections.Range[collections.Pair[asset.Pair, uint64]]{}).Values()
for _, market := range markets {
// disabled markets are not returned
if !market.Enabled {
if !req.Versioned && !market.Enabled {
continue
}

Expand Down
16 changes: 15 additions & 1 deletion x/perp/v2/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ func TestQueryMarkets(t *testing.T) {
),
).
Then(
QueryMarkets(QueryMarkets_MarketsShouldContain(types.DefaultMarket(pair))),
QueryMarkets(false, QueryMarkets_MarketsShouldContain(types.DefaultMarket(pair))),
QueryModuleAccounts(QueryModuleAccounts_ModulesBalanceShouldBe(
map[string]sdk.Coins{
"perp_ef": sdk.NewCoins(
Expand All @@ -358,6 +358,20 @@ func TestQueryMarkets(t *testing.T) {
},
)),
),
TC("versioned, all markets (active and inactive)").Given(
CreateCustomMarket("BTC:USD", WithVersion(1), WithEnabled(true)),
CreateCustomMarket("ETC:USD", WithVersion(1), WithEnabled(false)),
CreateCustomMarket("ETC:USD", WithVersion(2), WithEnabled(true)),
).Then(
QueryMarkets(true, QueryMarkets_ShouldLength(3)),
),
TC("not versioned, only active markets").Given(
CreateCustomMarket("BTC:USD", WithVersion(1), WithEnabled(true)),
CreateCustomMarket("ETC:USD", WithVersion(1), WithEnabled(false)),
CreateCustomMarket("ETC:USD", WithVersion(2), WithEnabled(true)),
).Then(
QueryMarkets(true, QueryMarkets_ShouldLength(3)),
),
}

NewTestSuite(t).WithTestCases(tc...).Run()
Expand Down
Loading

0 comments on commit a472744

Please sign in to comment.