github.com/gagliardetto/solana-go@v1.11.0/programs/serum/queue.go (about)

     1  // Copyright 2021 github.com/gagliardetto
     2  // This file has been modified by github.com/gagliardetto
     3  //
     4  // Copyright 2020 dfuse Platform Inc.
     5  //
     6  // Licensed under the Apache License, Version 2.0 (the "License");
     7  // you may not use this file except in compliance with the License.
     8  // You may obtain a copy of the License at
     9  //
    10  //      http://www.apache.org/licenses/LICENSE-2.0
    11  //
    12  // Unless required by applicable law or agreed to in writing, software
    13  // distributed under the License is distributed on an "AS IS" BASIS,
    14  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  package serum
    19  
    20  import (
    21  	"strings"
    22  
    23  	bin "github.com/gagliardetto/binary"
    24  	"github.com/gagliardetto/solana-go"
    25  )
    26  
    27  type RequestQueue struct {
    28  	SerumPadding [5]byte `json:"-"`
    29  
    30  	AccountFlags AccountFlag
    31  	Head         bin.Uint64 `bin:"sliceoffsetof=Requests,80"`
    32  
    33  	Count      bin.Uint64 `bin:"sizeof=Requests"`
    34  	NextSeqNum bin.Uint64
    35  	Requests   []*Request
    36  
    37  	EndPadding [7]byte `json:"-"`
    38  }
    39  
    40  func (r *RequestQueue) Decode(data []byte) error {
    41  	decoder := bin.NewBinDecoder(data)
    42  	return decoder.Decode(&r)
    43  }
    44  
    45  var _ bin.EncoderDecoder = &RequestQueue{}
    46  
    47  func (q *RequestQueue) UnmarshalWithDecoder(decoder *bin.Decoder) (err error) {
    48  	if err = decoder.SkipBytes(5); err != nil {
    49  		return err
    50  	}
    51  
    52  	if err = decoder.Decode(&q.AccountFlags); err != nil {
    53  		return err
    54  	}
    55  	if err = decoder.Decode(&q.Head); err != nil {
    56  		return err
    57  	}
    58  
    59  	if err = decoder.Decode(&q.Count); err != nil {
    60  		return err
    61  	}
    62  
    63  	if err = decoder.Decode(&q.NextSeqNum); err != nil {
    64  		return err
    65  	}
    66  
    67  	ringbufStartByte := decoder.Position()
    68  	ringbufByteSize := uint(decoder.Remaining() - 7)
    69  	ringbugLength := ringbufByteSize / EVENT_BYTE_SIZE
    70  
    71  	q.Requests = make([]*Request, q.Count)
    72  
    73  	for i := uint(0); i < uint(q.Count); i++ {
    74  		itemIndex := ((uint(q.Head) + i) % ringbugLength)
    75  		offset := ringbufStartByte + (itemIndex * EVENT_BYTE_SIZE)
    76  		if err = decoder.SetPosition(offset); err != nil {
    77  			return err
    78  		}
    79  
    80  		if err = decoder.Decode(&q.Requests[i]); err != nil {
    81  			return err
    82  		}
    83  	}
    84  
    85  	return nil
    86  }
    87  
    88  // TODO: fill up later
    89  func (q RequestQueue) MarshalWithEncoder(encoder *bin.Encoder) error {
    90  	return nil
    91  }
    92  
    93  type RequestFlag uint8
    94  
    95  const (
    96  	RequestFlagNewOrder = RequestFlag(1 << iota)
    97  	RequestFlagCancelOrder
    98  	RequestFlagBid
    99  	RequestFlagPostOnly
   100  	RequestFlagImmediateOrCancel
   101  	RequestFlagDecrementTakeOnSelfTrade
   102  )
   103  
   104  func (f RequestFlag) String() string {
   105  	var flags []string
   106  
   107  	if f.IsNewOrder() {
   108  		flags = append(flags, "NEW_ORDER")
   109  	}
   110  	if f.IsCancelOrder() {
   111  		flags = append(flags, "CANCEL_ORDER")
   112  	}
   113  	if f.IsBid() {
   114  		flags = append(flags, "BID")
   115  	} else {
   116  		flags = append(flags, "ASK")
   117  	}
   118  	if f.IsPostOnly() {
   119  		flags = append(flags, "POST_ONLY")
   120  	}
   121  	if f.IsImmediateOrCancel() {
   122  		flags = append(flags, "IMMEDIATE_OR_CANCEL")
   123  	}
   124  	if f.IsDecrementTakeOnSelfTrade() {
   125  		flags = append(flags, "DECR_TAKE_ON_SELF")
   126  	}
   127  	return strings.Join(flags, " | ")
   128  }
   129  
   130  func (r RequestFlag) IsNewOrder() bool {
   131  	return Has(uint8(r), uint8(RequestFlagNewOrder))
   132  }
   133  
   134  func (r RequestFlag) IsCancelOrder() bool {
   135  	return Has(uint8(r), uint8(RequestFlagCancelOrder))
   136  }
   137  
   138  func (r RequestFlag) IsBid() bool {
   139  	return Has(uint8(r), uint8(RequestFlagBid))
   140  }
   141  
   142  func (r RequestFlag) IsPostOnly() bool {
   143  	return Has(uint8(r), uint8(RequestFlagPostOnly))
   144  }
   145  
   146  func (r RequestFlag) IsImmediateOrCancel() bool {
   147  	return Has(uint8(r), uint8(RequestFlagImmediateOrCancel))
   148  }
   149  
   150  func (r RequestFlag) IsDecrementTakeOnSelfTrade() bool {
   151  	return Has(uint8(r), uint8(RequestFlagDecrementTakeOnSelfTrade))
   152  }
   153  
   154  // Size 80 byte
   155  type Request struct {
   156  	RequestFlags         RequestFlag
   157  	OwnerSlot            uint8
   158  	FeeTier              uint8
   159  	SelfTradeBehavior    uint8
   160  	Padding              [4]byte    `json:"-"`
   161  	MaxCoinQtyOrCancelId bin.Uint64 //the max amount you wish to buy or sell
   162  	NativePCQtyLocked    bin.Uint64
   163  	OrderID              bin.Uint128
   164  	OpenOrders           [4]bin.Uint64 // this is the openOrder address
   165  	ClientOrderID        bin.Uint64
   166  }
   167  
   168  func (r *Request) Equal(other *Request) bool {
   169  	//return (r.OrderID.Hi == other.OrderID.Hi && r.OrderID.Lo == other.OrderID.Lo) &&
   170  	//	(r.MaxCoinQtyOrCancelId == other.MaxCoinQtyOrCancelId) &&
   171  	//	(r.NativePCQtyLocked == other.NativePCQtyLocked)
   172  	return (r.OrderID.Hi == other.OrderID.Hi && r.OrderID.Lo == other.OrderID.Lo) &&
   173  		(r.MaxCoinQtyOrCancelId == other.MaxCoinQtyOrCancelId) &&
   174  		(r.NativePCQtyLocked == other.NativePCQtyLocked)
   175  }
   176  
   177  // -> 262144 + 12 bytes
   178  // -> 12 bytes of serum padding -> 262144
   179  // -> 262144 = HEADER + RING-BUFFER
   180  // -> HEADER = 32 bytes
   181  // -> RING BUFF = (262144 - 32)  262112
   182  // -> ring buf (262144 - 32) -> 262112 -> max number of event
   183  type EventQueue struct {
   184  	SerumPadding [5]byte `json:"-"`
   185  
   186  	AccountFlags AccountFlag
   187  	Head         bin.Uint64 `bin:"sliceoffsetof=Events,88"`
   188  	Count        bin.Uint64 `bin:"sizeof=Events"`
   189  	SeqNum       bin.Uint64
   190  	Events       []*Event
   191  
   192  	EndPadding [7]byte `json:"-"`
   193  }
   194  
   195  var _ bin.EncoderDecoder = &EventQueue{}
   196  
   197  func (q *EventQueue) Decode(data []byte) error {
   198  	decoder := bin.NewBinDecoder(data)
   199  	return decoder.Decode(&q)
   200  }
   201  
   202  func (q *EventQueue) UnmarshalWithDecoder(decoder *bin.Decoder) (err error) {
   203  	if err = decoder.SkipBytes(5); err != nil {
   204  		return err
   205  	}
   206  
   207  	if err = decoder.Decode(&q.AccountFlags); err != nil {
   208  		return err
   209  	}
   210  	if err = decoder.Decode(&q.Head); err != nil {
   211  		return err
   212  	}
   213  
   214  	if err = decoder.Decode(&q.Count); err != nil {
   215  		return err
   216  	}
   217  
   218  	if err = decoder.Decode(&q.SeqNum); err != nil {
   219  		return err
   220  	}
   221  
   222  	ringbufStartByte := decoder.Position()
   223  	ringbufByteSize := uint(decoder.Remaining() - 7)
   224  	ringbugLength := ringbufByteSize / EVENT_BYTE_SIZE
   225  
   226  	q.Events = make([]*Event, q.Count)
   227  
   228  	for i := uint(0); i < uint(q.Count); i++ {
   229  		itemIndex := ((uint(q.Head) + i) % ringbugLength)
   230  		offset := ringbufStartByte + (itemIndex * EVENT_BYTE_SIZE)
   231  		if err = decoder.SetPosition(offset); err != nil {
   232  			return err
   233  		}
   234  
   235  		if err = decoder.Decode(&q.Events[i]); err != nil {
   236  			return err
   237  		}
   238  	}
   239  
   240  	return nil
   241  }
   242  
   243  // TODO: fill up later
   244  func (q EventQueue) MarshalWithEncoder(encoder *bin.Encoder) error {
   245  	return nil
   246  }
   247  
   248  type EventFlag uint8
   249  
   250  const (
   251  	EventFlagFill  = 0x1
   252  	EventFlagOut   = 0x2
   253  	EventFlagBid   = 0x4
   254  	EventFlagMaker = 0x8
   255  
   256  	// Added in DEX v3
   257  
   258  	EventFlagReleaseFunds = 0x10
   259  )
   260  
   261  func (e EventFlag) IsFill() bool {
   262  	return Has(uint8(e), uint8(EventFlagFill))
   263  }
   264  
   265  func (e EventFlag) IsOut() bool {
   266  	return Has(uint8(e), uint8(EventFlagOut))
   267  }
   268  
   269  func (e EventFlag) IsBid() bool {
   270  	return Has(uint8(e), uint8(EventFlagBid))
   271  }
   272  
   273  func (e EventFlag) IsMaker() bool {
   274  	return Has(uint8(e), uint8(EventFlagMaker))
   275  }
   276  
   277  func (e EventFlag) IsReleaseFunds() bool {
   278  	return Has(uint8(e), uint8(EventFlagReleaseFunds))
   279  }
   280  
   281  func (e EventFlag) String() string {
   282  	var flags []string
   283  	if e.IsFill() {
   284  		flags = append(flags, "FILL")
   285  	}
   286  	if e.IsOut() {
   287  		flags = append(flags, "OUT")
   288  	}
   289  	if e.IsBid() {
   290  		flags = append(flags, "BID")
   291  	}
   292  	if e.IsMaker() {
   293  		flags = append(flags, "MAKER")
   294  	}
   295  	if e.IsReleaseFunds() {
   296  		flags = append(flags, "RELEASE_FUNDS")
   297  	}
   298  
   299  	return strings.Join(flags, " | ")
   300  }
   301  
   302  const EVENT_BYTE_SIZE = uint(88)
   303  
   304  type Event struct {
   305  	Flag              EventFlag
   306  	OwnerSlot         uint8
   307  	FeeTier           uint8
   308  	Padding           [5]uint8
   309  	NativeQtyReleased uint64 // the amount you should release (free to settle)
   310  	NativeQtyPaid     uint64 // The amount out of your account
   311  	NativeFeeOrRebate uint64 // maker etc...
   312  	OrderID           OrderID
   313  	Owner             solana.PublicKey // OpenOrder Account address NOT trader
   314  	ClientOrderID     uint64
   315  }
   316  
   317  /* Fill Event*/
   318  // BID: Buying Coin paying in PC
   319  // NativeQtyPaid will deplete PC
   320  // NativeQtyReleased: (native_qty_received) amount of Coin you received
   321  //	will incremet natice_coin_total, native_coin_free
   322  
   323  // ASK: Buying PC paying in COIN
   324  func (e *Event) Equal(other *Event) bool {
   325  	return e.OrderID.Hi == other.OrderID.Hi && e.OrderID.Lo == other.OrderID.Lo
   326  }
   327  
   328  func (e *Event) Side() Side {
   329  	if Has(uint8(e.Flag), uint8(EventFlagBid)) {
   330  		return SideBid
   331  	}
   332  	return SideAsk
   333  }
   334  
   335  func (e *Event) Filled() bool {
   336  	return Has(uint8(e.Flag), uint8(EventFlagFill))
   337  }
   338  
   339  func Has(b, flag uint8) bool { return b&flag == flag }