2020-11-05 14:54:08 -08:00
|
|
|
package serum
|
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
import (
|
2020-11-06 13:12:55 -08:00
|
|
|
"bytes"
|
2020-11-06 08:47:26 -08:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/dfuse-io/solana-go"
|
|
|
|
"github.com/lunixbochs/struc"
|
|
|
|
)
|
2020-11-05 14:54:08 -08:00
|
|
|
|
|
|
|
type MarketV2 struct {
|
|
|
|
/*
|
|
|
|
blob(5),
|
|
|
|
accountFlagsLayout('accountFlags'),
|
|
|
|
publicKeyLayout('ownAddress'),
|
|
|
|
u64('vaultSignerNonce'),
|
|
|
|
publicKeyLayout('baseMint'),
|
|
|
|
publicKeyLayout('quoteMint'),
|
|
|
|
publicKeyLayout('baseVault'),
|
|
|
|
u64('baseDepositsTotal'),
|
|
|
|
u64('baseFeesAccrued'),
|
|
|
|
publicKeyLayout('quoteVault'),
|
|
|
|
u64('quoteDepositsTotal'),
|
|
|
|
u64('quoteFeesAccrued'),
|
|
|
|
u64('quoteDustThreshold'),
|
|
|
|
publicKeyLayout('requestQueue'),
|
|
|
|
publicKeyLayout('eventQueue'),
|
|
|
|
publicKeyLayout('bids'),
|
2020-11-06 13:31:18 -08:00
|
|
|
|
2020-11-05 14:54:08 -08:00
|
|
|
publicKeyLayout('asks'),
|
|
|
|
u64('baseLotSize'),
|
|
|
|
u64('quoteLotSize'),
|
|
|
|
u64('feeRateBps'),
|
|
|
|
u64('referrerRebatesAccrued'),
|
|
|
|
blob(7),
|
|
|
|
*/
|
2020-11-06 10:18:04 -08:00
|
|
|
SerumPadding [5]byte `json:"-" struc:"[5]pad"`
|
2020-11-06 08:47:26 -08:00
|
|
|
AccountFlags solana.U64 `struc:"uint64,little"`
|
|
|
|
OwnAddress solana.PublicKey `struc:"[32]byte"`
|
|
|
|
VaultSignerNonce solana.U64 `struc:"uint64,little"`
|
|
|
|
BaseMint solana.PublicKey `struc:"[32]byte"`
|
|
|
|
QuoteMint solana.PublicKey `struc:"[32]byte"`
|
|
|
|
BaseVault solana.PublicKey `struc:"[32]byte"`
|
|
|
|
BaseDepositsTotal solana.U64 `struc:"uint64,little"`
|
|
|
|
BaseFeesAccrued solana.U64 `struc:"uint64,little"`
|
|
|
|
QuoteVault solana.PublicKey `struc:"[32]byte"`
|
|
|
|
QuoteDepositsTotal solana.U64 `struc:"uint64,little"`
|
|
|
|
QuoteFeesAccrued solana.U64 `struc:"uint64,little"`
|
|
|
|
QuoteDustThreshold solana.U64 `struc:"uint64,little"`
|
|
|
|
RequestQueue solana.PublicKey `struc:"[32]byte"`
|
|
|
|
EventQueue solana.PublicKey `struc:"[32]byte"`
|
|
|
|
Bids solana.PublicKey `struc:"[32]byte"`
|
|
|
|
Asks solana.PublicKey `struc:"[32]byte"`
|
|
|
|
BaseLotSize solana.U64 `struc:"uint64,little"`
|
|
|
|
QuoteLotSize solana.U64 `struc:"uint64,little"`
|
|
|
|
FeeRateBPS solana.U64 `struc:"uint64,little"`
|
|
|
|
ReferrerRebatesAccrued solana.U64 `struc:"uint64,little"`
|
2020-11-06 10:18:04 -08:00
|
|
|
EndPadding [7]byte `json:"-" struc:"[7]pad"`
|
2020-11-06 08:47:26 -08:00
|
|
|
}
|
2020-11-05 14:54:08 -08:00
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
type Orderbook struct {
|
|
|
|
// ORDERBOOK_LAYOUT
|
2020-11-06 10:18:04 -08:00
|
|
|
SerumPadding [5]byte `json:"-" struc:"[5]pad"`
|
2020-11-06 08:47:26 -08:00
|
|
|
AccountFlags solana.U64 `struc:"uint64,little"`
|
|
|
|
// SLAB_LAYOUT
|
|
|
|
// SLAB_HEADER_LAYOUT
|
2020-11-06 13:12:55 -08:00
|
|
|
BumpIndex uint32 `struc:"uint32,little,sizeof=Nodes"`
|
2020-11-06 10:18:04 -08:00
|
|
|
ZeroPaddingA [4]byte `json:"-" struc:"[4]pad"`
|
2020-11-06 08:47:26 -08:00
|
|
|
FreeListLen uint32 `struc:"uint32,little"`
|
2020-11-06 10:18:04 -08:00
|
|
|
ZeroPaddingB [4]byte `json:"-" struc:"[4]pad"`
|
2020-11-06 08:47:26 -08:00
|
|
|
FreeListHead uint32 `struc:"uint32,little"`
|
|
|
|
Root uint32 `struc:"uint32,little"`
|
|
|
|
LeafCount uint32 `struc:"uint32,little"`
|
2020-11-06 10:18:04 -08:00
|
|
|
ZeroPaddingC [4]byte `json:"-" struc:"[4]pad"`
|
2020-11-06 08:47:26 -08:00
|
|
|
// SLAB_NODE_LAYOUT
|
2020-11-06 11:43:44 -08:00
|
|
|
Nodes []SlabNode `struc:""`
|
2020-11-06 08:47:26 -08:00
|
|
|
}
|
2020-11-05 14:54:08 -08:00
|
|
|
|
2020-11-06 13:31:18 -08:00
|
|
|
func (o *Orderbook) Items(descending bool, f func(node *SlabLeafNode) error) error {
|
2020-11-06 10:18:04 -08:00
|
|
|
if o.LeafCount == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-11-07 18:30:28 -08:00
|
|
|
index := uint32(0)
|
2020-11-06 10:18:04 -08:00
|
|
|
stack := []uint32{o.Root}
|
2020-11-07 18:30:28 -08:00
|
|
|
for len(stack) > 0 {
|
|
|
|
index, stack = stack[len(stack)-1], stack[:len(stack)-1]
|
2020-11-06 10:18:04 -08:00
|
|
|
slab := o.Nodes[index]
|
2020-11-06 13:14:55 -08:00
|
|
|
impl, err := slab.Variant()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
switch s := impl.(type) {
|
2020-11-06 13:31:18 -08:00
|
|
|
case *SlabInnerNode:
|
2020-11-06 10:18:04 -08:00
|
|
|
if descending {
|
|
|
|
stack = append(stack, s.Children[0], s.Children[1])
|
|
|
|
} else {
|
|
|
|
stack = append(stack, s.Children[1], s.Children[0])
|
|
|
|
}
|
2020-11-06 13:31:18 -08:00
|
|
|
case *SlabLeafNode:
|
2020-11-06 10:18:04 -08:00
|
|
|
f(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
type SlabNode struct {
|
2020-11-06 13:12:55 -08:00
|
|
|
Type uint32 `struc:"uint32,little"`
|
|
|
|
Blob []byte `struc:"[68]byte"`
|
2020-11-06 08:47:26 -08:00
|
|
|
}
|
2020-11-05 14:54:08 -08:00
|
|
|
|
2020-11-06 13:12:55 -08:00
|
|
|
func (s *SlabNode) Variant() (interface{}, error) {
|
2020-11-06 11:43:44 -08:00
|
|
|
var el interface{}
|
|
|
|
switch s.Type {
|
|
|
|
case 0:
|
|
|
|
el = &SlabUninitialized{}
|
|
|
|
case 1:
|
|
|
|
el = &SlabInnerNode{}
|
|
|
|
case 2:
|
|
|
|
el = &SlabLeafNode{}
|
|
|
|
case 3:
|
|
|
|
el = &SlabFreeNode{}
|
|
|
|
case 4:
|
|
|
|
el = &SlabLastFreeNode{}
|
|
|
|
default:
|
2020-11-06 13:12:55 -08:00
|
|
|
return nil, fmt.Errorf("unsupported SlabNode variant %d", s.Type)
|
2020-11-06 11:43:44 -08:00
|
|
|
}
|
2020-11-06 13:12:55 -08:00
|
|
|
if err := struc.Unpack(bytes.NewReader(s.Blob), el); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return el, nil
|
2020-11-06 11:43:44 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
type SlabUninitialized struct {
|
|
|
|
}
|
2020-11-05 14:54:08 -08:00
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
type SlabInnerNode struct {
|
|
|
|
PrefixLen uint32 `struc:"uint32,little"`
|
2020-11-06 10:18:04 -08:00
|
|
|
// this corresponds to the uint128 key
|
2020-11-07 18:30:28 -08:00
|
|
|
KeySeq solana.U64 `struc:"uint64,little"`
|
|
|
|
KeyPrice solana.U64 `struc:"uint64,little"`
|
2020-11-06 10:18:04 -08:00
|
|
|
Children []uint32 `struc:"[2]uint32,little"`
|
2020-11-05 14:54:08 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 11:43:44 -08:00
|
|
|
type SlabLeafNode struct {
|
2020-11-06 10:18:04 -08:00
|
|
|
//u8('ownerSlot'), // Index into OPEN_ORDERS_LAYOUT.orders
|
|
|
|
//u8('feeTier'),
|
|
|
|
//blob(2),
|
|
|
|
//u128('key'), // (price, seqNum)
|
|
|
|
//publicKeyLayout('owner'), // Open orders account
|
|
|
|
//u64('quantity'), // In units of lot size
|
|
|
|
//u64('clientOrderId'),
|
2020-11-06 13:31:18 -08:00
|
|
|
OwnerSlot uint8 `struc:"uint8,little"`
|
|
|
|
FeeTier uint8 `struc:"uint8,little"`
|
|
|
|
Padding [2]byte `json:"-" struc:"[2]pad"`
|
|
|
|
|
2020-11-07 18:30:28 -08:00
|
|
|
Price solana.U128 `struc:"[16]byte,little"`
|
|
|
|
//KeySeq solana.U64 `struc:"uint64",little"`
|
|
|
|
//KeyPrice solana.U64 `struc:"uint64",little"`
|
2020-11-06 13:31:18 -08:00
|
|
|
|
2020-11-07 18:30:28 -08:00
|
|
|
Owner solana.PublicKey
|
|
|
|
Quantity solana.U64 `struc:"uint64,little"`
|
|
|
|
ClientOrderId solana.U64 `struc:"uint64,little"`
|
2020-11-06 08:47:26 -08:00
|
|
|
}
|
2020-11-05 14:54:08 -08:00
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
type SlabFreeNode struct {
|
|
|
|
Next uint32 `struc:"uint32,little"`
|
2020-11-05 14:54:08 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
type SlabLastFreeNode struct {
|
2020-11-05 14:54:08 -08:00
|
|
|
}
|