code.vegaprotocol.io/vega@v0.79.0/datanode/entities/order.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package entities
    17  
    18  import (
    19  	"encoding/hex"
    20  	"encoding/json"
    21  	"fmt"
    22  	"math"
    23  	"time"
    24  
    25  	"code.vegaprotocol.io/vega/core/types"
    26  	"code.vegaprotocol.io/vega/libs/ptr"
    27  	v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2"
    28  	"code.vegaprotocol.io/vega/protos/vega"
    29  
    30  	"github.com/shopspring/decimal"
    31  )
    32  
    33  type _Order struct{}
    34  
    35  type OrderID = ID[_Order]
    36  
    37  type Order struct {
    38  	ID              OrderID
    39  	MarketID        MarketID
    40  	PartyID         PartyID
    41  	Side            Side
    42  	Price           decimal.Decimal
    43  	Size            int64
    44  	Remaining       int64
    45  	TimeInForce     OrderTimeInForce
    46  	Type            OrderType
    47  	Status          OrderStatus
    48  	Reference       string
    49  	Reason          OrderError
    50  	Version         int32
    51  	PeggedOffset    decimal.Decimal
    52  	BatchID         int32
    53  	PeggedReference PeggedReference
    54  	LpID            []byte
    55  	CreatedAt       time.Time
    56  	UpdatedAt       time.Time
    57  	ExpiresAt       time.Time
    58  	TxHash          TxHash
    59  	VegaTime        time.Time
    60  	SeqNum          uint64
    61  	PostOnly        bool
    62  	ReduceOnly      bool
    63  
    64  	// Iceberg fields
    65  	ReservedRemaining  *int64
    66  	PeakSize           *int64
    67  	MinimumVisibleSize *int64
    68  }
    69  
    70  func (o Order) ToProto() *vega.Order {
    71  	var peggedOrder *vega.PeggedOrder
    72  	if o.PeggedReference != types.PeggedReferenceUnspecified {
    73  		peggedOrder = &vega.PeggedOrder{
    74  			Reference: o.PeggedReference,
    75  			Offset:    o.PeggedOffset.String(),
    76  		}
    77  	}
    78  
    79  	var reason *OrderError
    80  	if o.Reason != OrderErrorUnspecified {
    81  		reason = ptr.From(o.Reason)
    82  	}
    83  
    84  	var icebergOrder *vega.IcebergOrder
    85  	if o.PeakSize != nil {
    86  		icebergOrder = &vega.IcebergOrder{
    87  			ReservedRemaining:  uint64(*o.ReservedRemaining),
    88  			PeakSize:           uint64(*o.PeakSize),
    89  			MinimumVisibleSize: uint64(*o.MinimumVisibleSize),
    90  		}
    91  	}
    92  
    93  	vo := vega.Order{
    94  		Id:                   o.ID.String(),
    95  		MarketId:             o.MarketID.String(),
    96  		PartyId:              o.PartyID.String(),
    97  		Side:                 o.Side,
    98  		Price:                o.Price.String(),
    99  		Size:                 uint64(o.Size),
   100  		Remaining:            uint64(o.Remaining),
   101  		TimeInForce:          o.TimeInForce,
   102  		Type:                 o.Type,
   103  		CreatedAt:            o.CreatedAt.UnixNano(),
   104  		Status:               o.Status,
   105  		ExpiresAt:            o.ExpiresAt.UnixNano(),
   106  		Reference:            o.Reference,
   107  		Reason:               reason,
   108  		UpdatedAt:            o.UpdatedAt.UnixNano(),
   109  		Version:              uint64(o.Version),
   110  		BatchId:              uint64(o.BatchID),
   111  		PeggedOrder:          peggedOrder,
   112  		LiquidityProvisionId: hex.EncodeToString(o.LpID),
   113  		PostOnly:             o.PostOnly,
   114  		ReduceOnly:           o.ReduceOnly,
   115  		IcebergOrder:         icebergOrder,
   116  	}
   117  	return &vo
   118  }
   119  
   120  func (o Order) ToProtoEdge(_ ...any) (*v2.OrderEdge, error) {
   121  	return &v2.OrderEdge{
   122  		Node:   o.ToProto(),
   123  		Cursor: o.Cursor().Encode(),
   124  	}, nil
   125  }
   126  
   127  func OrderFromProto(po *vega.Order, seqNum uint64, txHash TxHash) (Order, error) {
   128  	price, err := decimal.NewFromString(po.Price)
   129  	if err != nil {
   130  		return Order{}, fmt.Errorf("price is not a valid integer: %v", po.Price)
   131  	}
   132  
   133  	if po.Size > math.MaxInt64 {
   134  		return Order{}, fmt.Errorf("size is larger than a 64-bit integer: %v", po.Size)
   135  	}
   136  	size := int64(po.Size)
   137  
   138  	if po.Remaining > math.MaxInt64 {
   139  		return Order{}, fmt.Errorf("remaining is larger than a 64-bit integer: %v", po.Remaining)
   140  	}
   141  	remaining := int64(po.Remaining)
   142  
   143  	if po.Version >= math.MaxInt32 {
   144  		return Order{}, fmt.Errorf("version is larger than a 32-bit integer: %v", po.Version)
   145  	}
   146  	version := int32(po.Version)
   147  
   148  	if po.BatchId >= math.MaxInt32 {
   149  		return Order{}, fmt.Errorf("batch ID is larger than a 32-bit integer: %v", po.Version)
   150  	}
   151  	batchID := int32(po.BatchId)
   152  
   153  	lpID, err := hex.DecodeString(po.LiquidityProvisionId)
   154  	if err != nil {
   155  		return Order{}, fmt.Errorf("liquidity Provision ID is not a valid hex string: %v", po.LiquidityProvisionId)
   156  	}
   157  
   158  	peggedOffset := decimal.Zero
   159  	var peggedReference types.PeggedReference
   160  	if po.PeggedOrder != nil {
   161  		peggedOffset, err = decimal.NewFromString(po.PeggedOrder.Offset)
   162  		if err != nil {
   163  			return Order{}, fmt.Errorf("pegged Offset not a valid decimal: %v", po.Price)
   164  		}
   165  		peggedReference = po.PeggedOrder.Reference
   166  	}
   167  
   168  	reason := OrderErrorUnspecified
   169  	if po.Reason != nil {
   170  		reason = *po.Reason
   171  	}
   172  
   173  	var PeakSize, MinimumVisibleSize, reservedRemaining *int64
   174  	if po.IcebergOrder != nil {
   175  		if po.IcebergOrder.ReservedRemaining > math.MaxInt64 {
   176  			return Order{}, fmt.Errorf("iceberg reserved remaining is larger than a 64-bit integer: %v", po.Remaining)
   177  		}
   178  		reservedRemaining = ptr.From(int64(po.IcebergOrder.ReservedRemaining))
   179  
   180  		if po.IcebergOrder.PeakSize > math.MaxInt64 {
   181  			return Order{}, fmt.Errorf("iceberg peak size is larger than a 64-bit integer: %v", po.Remaining)
   182  		}
   183  		PeakSize = ptr.From(int64(po.IcebergOrder.PeakSize))
   184  
   185  		if po.IcebergOrder.MinimumVisibleSize > math.MaxInt64 {
   186  			return Order{}, fmt.Errorf("iceberg minimum visible size is larger than a 64-bit integer: %v", po.Remaining)
   187  		}
   188  		MinimumVisibleSize = ptr.From(int64(po.IcebergOrder.MinimumVisibleSize))
   189  	}
   190  
   191  	o := Order{
   192  		ID:                 OrderID(po.Id),
   193  		MarketID:           MarketID(po.MarketId),
   194  		PartyID:            PartyID(po.PartyId),
   195  		Side:               po.Side,
   196  		Price:              price,
   197  		Size:               size,
   198  		Remaining:          remaining,
   199  		TimeInForce:        po.TimeInForce,
   200  		Type:               po.Type,
   201  		Status:             po.Status,
   202  		Reference:          po.Reference,
   203  		Reason:             reason,
   204  		Version:            version,
   205  		PeggedOffset:       peggedOffset,
   206  		BatchID:            batchID,
   207  		PeggedReference:    peggedReference,
   208  		LpID:               lpID,
   209  		CreatedAt:          NanosToPostgresTimestamp(po.CreatedAt),
   210  		UpdatedAt:          NanosToPostgresTimestamp(po.UpdatedAt),
   211  		ExpiresAt:          NanosToPostgresTimestamp(po.ExpiresAt),
   212  		SeqNum:             seqNum,
   213  		TxHash:             txHash,
   214  		PostOnly:           po.PostOnly,
   215  		ReduceOnly:         po.ReduceOnly,
   216  		ReservedRemaining:  reservedRemaining,
   217  		PeakSize:           PeakSize,
   218  		MinimumVisibleSize: MinimumVisibleSize,
   219  	}
   220  
   221  	return o, nil
   222  }
   223  
   224  type OrderKey struct {
   225  	ID       OrderID
   226  	Version  int32
   227  	VegaTime time.Time
   228  }
   229  
   230  func (o Order) Key() OrderKey {
   231  	return OrderKey{o.ID, o.Version, o.VegaTime}
   232  }
   233  
   234  func (o Order) ToRow() []interface{} {
   235  	return []interface{}{
   236  		o.ID, o.MarketID, o.PartyID, o.Side, o.Price,
   237  		o.Size, o.Remaining, o.TimeInForce, o.Type, o.Status,
   238  		o.Reference, o.Reason, o.Version, o.PeggedOffset, o.BatchID,
   239  		o.PeggedReference, o.LpID, o.CreatedAt, o.UpdatedAt, o.ExpiresAt,
   240  		o.TxHash, o.VegaTime, o.SeqNum, o.PostOnly, o.ReduceOnly, o.ReservedRemaining,
   241  		o.PeakSize, o.MinimumVisibleSize,
   242  	}
   243  }
   244  
   245  var OrderColumns = []string{
   246  	"id", "market_id", "party_id", "side", "price",
   247  	"size", "remaining", "time_in_force", "type", "status",
   248  	"reference", "reason", "version", "pegged_offset", "batch_id",
   249  	"pegged_reference", "lp_id", "created_at", "updated_at", "expires_at",
   250  	"tx_hash", "vega_time", "seq_num", "post_only", "reduce_only", "reserved_remaining",
   251  	"peak_size", "minimum_visible_size",
   252  }
   253  
   254  type OrderCursor struct {
   255  	CreatedAt time.Time `json:"createdAt"`
   256  	ID        OrderID   `json:"id"`
   257  	VegaTime  time.Time `json:"vegaTime"`
   258  }
   259  
   260  func (oc *OrderCursor) Parse(cursorString string) error {
   261  	if cursorString == "" {
   262  		return nil
   263  	}
   264  	return json.Unmarshal([]byte(cursorString), oc)
   265  }
   266  
   267  func (oc OrderCursor) String() string {
   268  	bs, err := json.Marshal(oc)
   269  	if err != nil {
   270  		// This should never happen.
   271  		panic(fmt.Errorf("could not marshal order cursor: %w", err))
   272  	}
   273  	return string(bs)
   274  }
   275  
   276  func (o Order) Cursor() *Cursor {
   277  	cursor := OrderCursor{
   278  		CreatedAt: o.CreatedAt,
   279  		ID:        o.ID,
   280  		VegaTime:  o.VegaTime,
   281  	}
   282  
   283  	return NewCursor(cursor.String())
   284  }