Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

only create clob pair during deliver tx and cli cmd for pml #2272

Merged
merged 5 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions protocol/testutil/keeper/listing.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func ListingKeepers(
// Define necessary keepers here for unit tests
memClob := &mocks.MemClob{}
memClob.On("SetClobKeeper", mock.Anything).Return()
memClob.On("CreateOrderbook", mock.Anything, mock.Anything).Return(nil)
epochsKeeper, _ := createEpochsKeeper(stateStore, db, cdc)

accountsKeeper, _ := createAccountKeeper(
Expand Down
119 changes: 72 additions & 47 deletions protocol/x/clob/keeper/clob_pair.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func clobPairKey(
// CreatePerpetualClobPair creates a new perpetual CLOB pair in the store.
// Additionally, it creates an order book matching the ID of the newly created CLOB pair.
//
// An error will occur if any of the fields fail validation (see validateClobPair for details),
// An error will occur if any of the fields fail validation (see ValidateClobPair for details),
// or if the `perpetualId` cannot be found.
// In the event of an error, the store will not be updated nor will a matching order book be created.
//
Expand All @@ -50,26 +50,6 @@ func (k Keeper) CreatePerpetualClobPair(
subticksPerTick uint32,
status types.ClobPair_Status,
) (types.ClobPair, error) {
// If the desired CLOB pair ID is already in use, return an error.
if clobPair, exists := k.GetClobPair(ctx, types.ClobPairId(clobPairId)); exists {
return types.ClobPair{}, errorsmod.Wrapf(
types.ErrClobPairAlreadyExists,
"id=%v, existing clob pair=%v",
clobPairId,
clobPair,
)
}

// Verify the perpetual ID is not already associated with an existing CLOB pair.
if clobPairId, found := k.PerpetualIdToClobPairId[perpetualId]; found {
return types.ClobPair{}, errorsmod.Wrapf(
types.ErrPerpetualAssociatedWithExistingClobPair,
"perpetual id=%v, existing clob pair id=%v",
perpetualId,
clobPairId,
)
}

clobPair := types.ClobPair{
Metadata: &types.ClobPair_PerpetualClobMetadata{
PerpetualClobMetadata: &types.PerpetualClobMetadata{
Expand All @@ -82,39 +62,52 @@ func (k Keeper) CreatePerpetualClobPair(
SubticksPerTick: subticksPerTick,
Status: status,
}
if err := k.validateClobPair(ctx, &clobPair); err != nil {
if err := k.ValidateClobPairCreation(ctx, &clobPair); err != nil {
return clobPair, err
}
perpetual, err := k.perpetualsKeeper.GetPerpetual(ctx, perpetualId)

err := k.CreateClobPair(ctx, clobPair)
if err != nil {
return clobPair, err
}

k.createClobPair(ctx, clobPair)
k.GetIndexerEventManager().AddTxnEvent(
ctx,
indexerevents.SubtypePerpetualMarket,
indexerevents.PerpetualMarketEventVersion,
indexer_manager.GetBytes(
indexerevents.NewPerpetualMarketCreateEvent(
perpetualId,
clobPairId,
perpetual.Params.Ticker,
perpetual.Params.MarketId,
status,
quantumConversionExponent,
perpetual.Params.AtomicResolution,
subticksPerTick,
stepSizeBaseQuantums.ToUint64(),
perpetual.Params.LiquidityTier,
perpetual.Params.MarketType,
),
),
)

return clobPair, nil
}

// ValidateClobPairCreation validates a CLOB pair's fields are suitable for CLOB pair creation
// and that the perpetual ID is associated with an existing perpetual.
func (k Keeper) ValidateClobPairCreation(ctx sdk.Context, clobPair *types.ClobPair) error {
// If the desired CLOB pair ID is already in use, return an error.
if clobPair, exists := k.GetClobPair(ctx, clobPair.GetClobPairId()); exists {
return errorsmod.Wrapf(
types.ErrClobPairAlreadyExists,
"id=%v, existing clob pair=%v",
clobPair.Id,
clobPair,
)
}

perpetualId, err := clobPair.GetPerpetualId()
if err != nil {
return errorsmod.Wrap(
types.ErrInvalidClobPairParameter,
err.Error(),
)
}

// Verify the perpetual ID is not already associated with an existing CLOB pair.
if clobPairId, found := k.PerpetualIdToClobPairId[perpetualId]; found {
return errorsmod.Wrapf(
types.ErrPerpetualAssociatedWithExistingClobPair,
"perpetual id=%v, existing clob pair id=%v",
perpetualId,
clobPairId,
)
}

return k.validateClobPair(ctx, clobPair)
}

// validateClobPair validates a CLOB pair's fields are suitable for CLOB pair creation.
//
// Stateful Validation:
Expand Down Expand Up @@ -169,9 +162,9 @@ func (k Keeper) createOrderbook(ctx sdk.Context, clobPair types.ClobPair) {
k.MemClob.CreateOrderbook(clobPair)
}

// createClobPair creates a new `ClobPair` in the store and creates the corresponding orderbook in the memclob.
// CreateClobPair creates a new `ClobPair` in the store and creates the corresponding orderbook in the memclob.
// This function returns an error if a value for the ClobPair's id already exists in state.
func (k Keeper) createClobPair(ctx sdk.Context, clobPair types.ClobPair) {
func (k Keeper) CreateClobPair(ctx sdk.Context, clobPair types.ClobPair) error {
// Validate the given clob pair id is not already in use.
if _, exists := k.GetClobPair(ctx, clobPair.GetClobPairId()); exists {
panic(
Expand All @@ -190,6 +183,38 @@ func (k Keeper) createClobPair(ctx sdk.Context, clobPair types.ClobPair) {

// Create the mapping between clob pair and perpetual.
k.SetClobPairIdForPerpetual(ctx, clobPair)

perpetualId, err := clobPair.GetPerpetualId()
if err != nil {
panic(err)
}
perpetual, err := k.perpetualsKeeper.GetPerpetual(ctx, perpetualId)
if err != nil {
return err
}

k.GetIndexerEventManager().AddTxnEvent(
ctx,
indexerevents.SubtypePerpetualMarket,
indexerevents.PerpetualMarketEventVersion,
indexer_manager.GetBytes(
indexerevents.NewPerpetualMarketCreateEvent(
perpetualId,
clobPair.Id,
perpetual.Params.Ticker,
perpetual.Params.MarketId,
clobPair.Status,
clobPair.QuantumConversionExponent,
perpetual.Params.AtomicResolution,
clobPair.SubticksPerTick,
clobPair.StepBaseQuantums,
perpetual.Params.LiquidityTier,
perpetual.Params.MarketType,
),
),
)

return nil
}

// setClobPair sets a specific `ClobPair` in the store from its index.
Expand Down
37 changes: 37 additions & 0 deletions protocol/x/listing/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package cli
import (
"fmt"

"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"

"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
Expand All @@ -19,5 +23,38 @@ func GetTxCmd() *cobra.Command {
RunE: client.ValidateCmd,
}

cmd.AddCommand(CmdCreateMarketPermissionless())

return cmd
}

// CmdCreateMarketPermissionless is the CLI command for creating a permissionless market.
func CmdCreateMarketPermissionless() *cobra.Command {
cmd := &cobra.Command{
Use: "create-market [ticker] [address]",
Short: "Create new market with permissionless access",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) (err error) {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
ticker, address := args[0], args[1]

// Create MsgCreateMarketPermissionless.
msg := &types.MsgCreateMarketPermissionless{
Ticker: ticker,
SubaccountId: &satypes.SubaccountId{
Owner: address,
Number: 0,
},
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
40 changes: 26 additions & 14 deletions protocol/x/listing/keeper/listing.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package keeper
import (
"math"

"github.com/dydxprotocol/v4-chain/protocol/lib"

"github.com/dydxprotocol/v4-chain/protocol/lib/slinky"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -11,7 +13,6 @@ import (
"github.com/dydxprotocol/v4-chain/protocol/x/listing/types"
perpetualtypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"
"github.com/skip-mev/slinky/x/marketmap/types/tickermetadata"
)

Expand Down Expand Up @@ -84,20 +85,31 @@ func (k Keeper) CreateClobPair(
) (clobPairId uint32, err error) {
clobPairId = k.ClobKeeper.AcquireNextClobPairID(ctx)

// Create a new clob pair
clobPair, err := k.ClobKeeper.CreatePerpetualClobPair(
ctx,
clobPairId,
perpetualId,
satypes.BaseQuantums(types.DefaultStepBaseQuantums),
types.DefaultQuantumConversionExponent,
types.SubticksPerTick_LongTail,
clobtypes.ClobPair_STATUS_ACTIVE,
)
if err != nil {
clobPair := clobtypes.ClobPair{
Metadata: &clobtypes.ClobPair_PerpetualClobMetadata{
PerpetualClobMetadata: &clobtypes.PerpetualClobMetadata{
PerpetualId: perpetualId,
},
},
Id: clobPairId,
StepBaseQuantums: types.DefaultStepBaseQuantums,
QuantumConversionExponent: types.DefaultQuantumConversionExponent,
SubticksPerTick: types.SubticksPerTick_LongTail,
Status: clobtypes.ClobPair_STATUS_ACTIVE,
}
if err := k.ClobKeeper.ValidateClobPairCreation(ctx, &clobPair); err != nil {
return 0, err
}

// Only create the clob pair if we are in deliver tx mode. This is to prevent populating
// in memory data structures in the CLOB during simulation mode.
if lib.IsDeliverTxMode(ctx) {
err := k.ClobKeeper.CreateClobPair(ctx, clobPair)
if err != nil {
return 0, err
}
}

return clobPair.Id, nil
}

Expand All @@ -118,11 +130,11 @@ func (k Keeper) CreatePerpetual(
}
marketMapDetails, err := k.MarketMapKeeper.GetMarket(ctx, marketMapPair.String())
if err != nil {
return 0, err
return 0, types.ErrMarketNotFound
}
metadata, err := tickermetadata.DyDxFromJSONString(marketMapDetails.Ticker.Metadata_JSON)
if err != nil {
return 0, err
return 0, types.ErrInvalidMarketMapTickerMetadata
}
if metadata.ReferencePrice == 0 {
return 0, types.ErrReferencePriceZero
Expand Down
Loading
Loading