Skip to content

Commit

Permalink
only create clob pair during deliver tx and cli cmd for pml (#2272)
Browse files Browse the repository at this point in the history
Signed-off-by: Shrenuj Bansal <[email protected]>
  • Loading branch information
shrenujb authored Sep 18, 2024
1 parent 3cb2978 commit ba731b0
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 61 deletions.
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

0 comments on commit ba731b0

Please sign in to comment.