github.com/gagliardetto/solana-go@v1.11.0/programs/serum/types.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 package serum 18 19 import ( 20 "encoding/binary" 21 "encoding/hex" 22 "fmt" 23 "math/big" 24 25 bin "github.com/gagliardetto/binary" 26 "github.com/gagliardetto/solana-go" 27 "go.uber.org/zap" 28 ) 29 30 type AccountFlag uint64 31 32 const ( 33 AccountFlagInitialized = AccountFlag(1 << iota) 34 AccountFlagMarket 35 AccountFlagOpenOrders 36 AccountFlagRequestQueue 37 AccountFlagEventQueue 38 AccountFlagBids 39 AccountFlagAsks 40 AccountFlagDisabled 41 ) 42 43 func (a *AccountFlag) Is(flag AccountFlag) bool { return *a&flag != 0 } 44 func (a *AccountFlag) String() string { 45 status := "unknown" 46 account_type := "unknown" 47 if a.Is(AccountFlagInitialized) { 48 status = "initialized" 49 } else if a.Is(AccountFlagDisabled) { 50 status = "disabled" 51 } 52 if a.Is(AccountFlagMarket) { 53 account_type = "market" 54 } else if a.Is(AccountFlagOpenOrders) { 55 account_type = "open orders" 56 } else if a.Is(AccountFlagRequestQueue) { 57 account_type = "request queue" 58 } else if a.Is(AccountFlagEventQueue) { 59 account_type = "event queue" 60 } else if a.Is(AccountFlagBids) { 61 account_type = "bids" 62 } else if a.Is(AccountFlagAsks) { 63 account_type = "asks" 64 } 65 return fmt.Sprintf("%s %s", status, account_type) 66 } 67 68 type Side uint32 69 70 const ( 71 SideBid = iota 72 SideAsk 73 ) 74 75 type MarketV2 struct { 76 SerumPadding [5]byte `json:"-"` 77 AccountFlags AccountFlag 78 OwnAddress solana.PublicKey 79 VaultSignerNonce bin.Uint64 80 BaseMint solana.PublicKey 81 QuoteMint solana.PublicKey 82 BaseVault solana.PublicKey 83 BaseDepositsTotal bin.Uint64 84 BaseFeesAccrued bin.Uint64 85 QuoteVault solana.PublicKey 86 QuoteDepositsTotal bin.Uint64 87 QuoteFeesAccrued bin.Uint64 88 QuoteDustThreshold bin.Uint64 89 RequestQueue solana.PublicKey 90 EventQueue solana.PublicKey 91 Bids solana.PublicKey 92 Asks solana.PublicKey 93 BaseLotSize bin.Uint64 94 QuoteLotSize bin.Uint64 95 FeeRateBPS bin.Uint64 96 ReferrerRebatesAccrued bin.Uint64 97 EndPadding [7]byte `json:"-"` 98 } 99 100 func (m *MarketV2) Decode(in []byte) error { 101 decoder := bin.NewBinDecoder(in) 102 err := decoder.Decode(&m) 103 if err != nil { 104 return fmt.Errorf("unpack: %w", err) 105 } 106 return nil 107 } 108 109 type Orderbook struct { 110 SerumPadding [5]byte `json:"-"` 111 AccountFlags AccountFlag 112 BumpIndex uint32 `bin:"sizeof=Nodes"` 113 ZeroPaddingA [4]byte `json:"-"` 114 FreeListLen uint32 115 ZeroPaddingB [4]byte `json:"-"` 116 FreeListHead uint32 117 Root uint32 118 LeafCount uint32 119 ZeroPaddingC [4]byte `json:"-"` 120 Nodes []*Slab 121 } 122 123 func (o *Orderbook) Items(descending bool, f func(node *SlabLeafNode) error) error { 124 if o.LeafCount == 0 { 125 return nil 126 } 127 128 index := uint32(0) 129 stack := []uint32{o.Root} 130 for len(stack) > 0 { 131 index, stack = stack[len(stack)-1], stack[:len(stack)-1] 132 if traceEnabled { 133 zlog.Debug("looking at slab index", zap.Int("index", int(index))) 134 } 135 slab := o.Nodes[index] 136 impl := slab.Impl 137 switch s := impl.(type) { 138 case *SlabInnerNode: 139 if descending { 140 stack = append(stack, s.Children[0], s.Children[1]) 141 } else { 142 stack = append(stack, s.Children[1], s.Children[0]) 143 } 144 case *SlabLeafNode: 145 if traceEnabled { 146 zlog.Debug("found leaf", zap.Int("leaf", int(index))) 147 } 148 if err := f(s); err != nil { 149 return err 150 } 151 } 152 } 153 return nil 154 } 155 156 var SlabFactoryImplDef = bin.NewVariantDefinition(bin.Uint32TypeIDEncoding, []bin.VariantType{ 157 {Name: "uninitialized", Type: (*SlabUninitialized)(nil)}, 158 {Name: "inner_node", Type: (*SlabInnerNode)(nil)}, 159 {Name: "leaf_node", Type: (*SlabLeafNode)(nil)}, 160 {Name: "free_node", Type: (*SlabFreeNode)(nil)}, 161 {Name: "last_free_node", Type: (*SlabLastFreeNode)(nil)}, 162 }) 163 164 type Slab struct { 165 bin.BaseVariant 166 } 167 168 var _ bin.EncoderDecoder = &Slab{} 169 170 func (s *Slab) UnmarshalWithDecoder(decoder *bin.Decoder) error { 171 return s.BaseVariant.UnmarshalBinaryVariant(decoder, SlabFactoryImplDef) 172 } 173 174 func (s Slab) MarshalWithEncoder(encoder *bin.Encoder) error { 175 err := encoder.WriteUint32(s.TypeID.Uint32(), binary.LittleEndian) 176 if err != nil { 177 return err 178 } 179 return encoder.Encode(s.Impl) 180 } 181 182 type SlabUninitialized struct { 183 Padding [4]byte `json:"-"` 184 PaddingA [64]byte `json:"-"` // ensure variant is 68 bytes 185 } 186 187 type SlabInnerNode struct { 188 PrefixLen uint32 189 Key bin.Uint128 190 Children [2]uint32 191 Padding [40]byte `json:"-"` // ensure variant is 68 bytes 192 } 193 194 type SlabFreeNode struct { 195 Next uint32 196 Padding [64]byte `json:"-"` // ensure variant is 68 bytes 197 } 198 199 type SlabLastFreeNode struct { 200 Padding [4]byte `json:"-"` 201 PaddingA [64]byte `json:"-"` // ensure variant is 68 bytes 202 } 203 204 type SlabLeafNode struct { 205 OwnerSlot uint8 206 FeeTier uint8 207 Padding [2]byte `json:"-"` 208 Key bin.Uint128 209 Owner solana.PublicKey 210 Quantity bin.Uint64 211 ClientOrderId bin.Uint64 212 } 213 214 func (s *SlabLeafNode) GetPrice() *big.Int { 215 raw := s.Key.BigInt().Bytes() 216 if len(raw) <= 8 { 217 return big.NewInt(0) 218 } 219 v := new(big.Int).SetBytes(raw[0 : len(raw)-8]) 220 return v 221 } 222 223 type OrderID bin.Uint128 224 225 func NewOrderID(orderID string) (OrderID, error) { 226 d, err := hex.DecodeString(orderID) 227 if err != nil { 228 return OrderID(bin.Uint128{ 229 Lo: 0, 230 Hi: 0, 231 }), fmt.Errorf("unable to decode order ID: %w", err) 232 } 233 234 if len(d) < 16 { 235 return OrderID(bin.Uint128{ 236 Lo: 0, 237 Hi: 0, 238 }), fmt.Errorf("order ID too short expecting at least 16 bytes got %d", len(d)) 239 } 240 241 return OrderID(bin.Uint128{ 242 Lo: binary.BigEndian.Uint64(d[8:]), 243 Hi: binary.BigEndian.Uint64(d[:8]), 244 }), nil 245 } 246 247 func (o OrderID) Price() uint64 { 248 return o.Hi 249 } 250 251 func (o OrderID) HexString(withPrefix bool) string { 252 number := make([]byte, 16) 253 binary.BigEndian.PutUint64(number[:], o.Hi) // old price 254 binary.BigEndian.PutUint64(number[8:], o.Lo) // old seq_number 255 str := hex.EncodeToString(number) 256 if withPrefix { 257 return "0x" + str 258 } 259 return str 260 } 261 262 func (o OrderID) SeqNum(side Side) uint64 { 263 if side == SideBid { 264 return ^o.Lo 265 } 266 267 return o.Lo 268 } 269 270 type OpenOrders struct { 271 SerumPadding [5]byte `json:"-"` 272 AccountFlags AccountFlag 273 Market solana.PublicKey 274 Owner solana.PublicKey 275 NativeBaseTokenFree bin.Uint64 276 NativeBaseTokenTotal bin.Uint64 277 NativeQuoteTokenFree bin.Uint64 278 NativeQuoteTokenTotal bin.Uint64 279 FreeSlotBits bin.Uint128 280 IsBidBits bin.Uint128 // Bids is 1, Ask is 0 281 Orders [128]OrderID 282 ClientOrderIDs [128]bin.Uint64 283 ReferrerRebatesAccrued bin.Uint64 284 EndPadding [7]byte `json:"-"` 285 } 286 287 type Order struct { 288 ID OrderID 289 Side Side 290 } 291 292 func (o *Order) SeqNum() uint64 { 293 return o.ID.SeqNum(o.Side) 294 } 295 296 func (o *Order) Price() uint64 { 297 return o.ID.Price() 298 } 299 300 func (o *OpenOrders) GetOrder(index uint32) *Order { 301 order := &Order{ 302 ID: o.Orders[index], 303 Side: SideBid, 304 } 305 isZero, err := IsBitZero(o.IsBidBits, index) 306 if err != nil { 307 panic("this should never happen") 308 } 309 if isZero { 310 order.Side = SideAsk 311 } 312 return order 313 } 314 315 func (o *OpenOrders) Decode(in []byte) error { 316 decoder := bin.NewBinDecoder(in) 317 err := decoder.Decode(&o) 318 if err != nil { 319 return fmt.Errorf("unpack: %w", err) 320 } 321 return nil 322 } 323 324 func IsBitZero(v bin.Uint128, bitIndex uint32) (bool, error) { 325 if bitIndex > 127 { 326 return false, fmt.Errorf("bit index out of range") 327 } 328 329 if bitIndex > 63 { 330 bitIndex = bitIndex - 64 331 mask := uint64(1 << bitIndex) 332 return (v.Hi&mask == 0), nil 333 } 334 mask := uint64(1 << bitIndex) 335 return (v.Lo&mask == 0), nil 336 }