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 }