2020-11-05 14:54:08 -08:00
|
|
|
package serum
|
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"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'),
|
|
|
|
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
|
|
|
|
BumpIndex uint32 `struc:"uint32,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 10:18:04 -08:00
|
|
|
func (o *Orderbook) Items(descending bool, f func(node SlackLeafNode) error) error {
|
|
|
|
if o.LeafCount == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
itr := 0
|
|
|
|
stack := []uint32{o.Root}
|
|
|
|
for itr < len(stack) {
|
|
|
|
index := stack[itr]
|
|
|
|
slab := o.Nodes[index]
|
|
|
|
switch s := slab.Impl.(type) {
|
|
|
|
case SlabInnerNode:
|
|
|
|
if descending {
|
|
|
|
stack = append(stack, s.Children[0], s.Children[1])
|
|
|
|
} else {
|
|
|
|
stack = append(stack, s.Children[1], s.Children[0])
|
|
|
|
|
|
|
|
}
|
|
|
|
case SlackLeafNode:
|
|
|
|
f(s)
|
|
|
|
}
|
|
|
|
itr++
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
var slabInstructionDef = solana.NewVariantDefinition([]solana.VariantType{
|
|
|
|
{"uninitialized", (*SlabUninitialized)(nil)},
|
|
|
|
{"innerNode", (*SlabInnerNode)(nil)},
|
2020-11-06 11:43:44 -08:00
|
|
|
{"leafNode", (*SlabLeafNode)(nil)},
|
2020-11-06 08:47:26 -08:00
|
|
|
{"freeNode", (*SlabFreeNode)(nil)},
|
|
|
|
{"lastFreeNode", (*SlabLastFreeNode)(nil)},
|
|
|
|
})
|
2020-11-05 14:54:08 -08:00
|
|
|
|
2020-11-06 08:47:26 -08:00
|
|
|
type SlabNode struct {
|
2020-11-06 11:43:44 -08:00
|
|
|
Type solana.Varuint16
|
|
|
|
Variant interface{}
|
2020-11-06 08:47:26 -08:00
|
|
|
}
|
2020-11-05 14:54:08 -08:00
|
|
|
|
2020-11-06 11:43:44 -08:00
|
|
|
func (s *SlabNode) Unpack(r io.Reader, length int, opt *struc.Options) (err error) {
|
|
|
|
fmt.Println("Unpacking SlabNode")
|
|
|
|
|
|
|
|
if err = struc.Unpack(r, &s.Type); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
|
|
|
return fmt.Errorf("unsupported SlabNode variant %d", s.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
return struc.Unpack(r, el)
|
2020-11-06 08:47:26 -08:00
|
|
|
}
|
2020-11-05 14:54:08 -08:00
|
|
|
|
2020-11-06 11:43:44 -08:00
|
|
|
func (s SlabNode) Pack(p []byte, opt *struc.Options) (written int, err error) {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s SlabNode) Size(opt *struc.Options) int { return 0 }
|
|
|
|
|
|
|
|
func (s SlabNode) String() string { return fmt.Sprintf("variant %d, %T", s.Type, s.Variant) }
|
|
|
|
|
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
|
|
|
|
KeyPrice solana.U64 `struc:"uint64",little"`
|
|
|
|
KeySeq solana.U64 `struc:"uint64",little"`
|
|
|
|
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'),
|
|
|
|
OwnerSlot uint8 `struc:"uint8,little"`
|
|
|
|
FeeTier uint8 `struc:"uint8,little"`
|
|
|
|
Padding [2]byte `json:"-" struc:"[2]pad"`
|
|
|
|
KeyPrice solana.U64 `struc:"uint64",little"`
|
|
|
|
KeySeq solana.U64 `struc:"uint64",little"`
|
|
|
|
Owner solana.PublicKey `struc:"[32]byte"`
|
|
|
|
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
|
|
|
}
|