Skip to content
This repository was archived by the owner on May 31, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 19 additions & 37 deletions types.go → accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package pyth

import (
"bytes"
"errors"

bin "github.com/gagliardetto/binary"
Expand Down Expand Up @@ -60,25 +59,12 @@ func PeekAccount(data []byte) uint32 {
return header.AccountType
}

// readLPString returns a length-prefixed string as seen in ProductAccount.Attrs.
func readLPString(rd *bytes.Reader) (string, error) {
strLen, err := rd.ReadByte()
if err != nil {
return "", err
}
val := make([]byte, strLen)
if _, err := rd.Read(val); err != nil {
return "", err
}
return string(val), nil
}

// ProductAccount contains metadata for a single product,
// such as its symbol and its base/quote currencies.
type ProductAccount struct {
AccountHeader
FirstPrice solana.PublicKey // first price account in list
Attrs [464]byte // key-value string pairs of additional data
AttrsData [464]byte // key-value string pairs of additional data
}

// UnmarshalBinary decodes the product account from the on-chain format.
Expand All @@ -96,30 +82,18 @@ func (p *ProductAccount) UnmarshalBinary(buf []byte) error {
return nil
}

// GetAttrs returns the parsed set of key-value pairs.
func (p *ProductAccount) GetAttrs() (map[string]string, error) {
kvps := make(map[string]string)

attrs := p.Attrs[:]
// GetAttrsMap returns the parsed set of key-value pairs.
func (p *ProductAccount) GetAttrsMap() (AttrsMap, error) {
// Length of attrs is determined by size value in header.
data := p.AttrsData[:]
maxSize := int(p.Size) - 48
if maxSize > 0 && len(attrs) > maxSize {
attrs = attrs[:maxSize]
if maxSize > 0 && len(data) > maxSize {
data = data[:maxSize]
}

rd := bytes.NewReader(attrs)
for rd.Len() > 0 {
key, err := readLPString(rd)
if err != nil {
return kvps, err
}
val, err := readLPString(rd)
if err != nil {
return kvps, err
}
kvps[key] = val
}

return kvps, nil
// Unmarshal attrs.
var attrs AttrsMap
err := attrs.UnmarshalBinary(data)
return attrs, err
}

// Ema is an exponentially-weighted moving average.
Expand All @@ -140,6 +114,14 @@ type PriceInfo struct {
PubSlot uint64 // valid publishing slot
}

// Price status.
const (
PriceStatusUnknown = uint32(iota)
PriceStatusTrading
PriceStatusHalted
PriceStatusAuction
)

// PriceComp contains the price and confidence contributed by a specific publisher.
type PriceComp struct {
Publisher solana.PublicKey // key of contributing publisher
Expand Down
210 changes: 105 additions & 105 deletions types_test.go → accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import (
)

var (
//go:embed tests/EWxGfxoPQSNA2744AYdAKmsQZ8F9o9M7oKkvL3VM1dko.bin
//go:embed tests/product_account/EWxGfxoPQSNA2744AYdAKmsQZ8F9o9M7oKkvL3VM1dko.bin
caseProductAccount []byte
//go:embed tests/E36MyBbavhYKHVLWR79GiReNNnBDiHj6nWA7htbkNZbh.bin
//go:embed tests/price_account/E36MyBbavhYKHVLWR79GiReNNnBDiHj6nWA7htbkNZbh.bin
casePriceAccount []byte
//go:embed tests/BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2.bin
//go:embed tests/mapping_account/BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2.bin
caseMappingAccount []byte
)

Expand All @@ -41,7 +41,7 @@ func TestProductAccount(t *testing.T) {
Size: 161,
},
FirstPrice: solana.MustPublicKeyFromBase58("E36MyBbavhYKHVLWR79GiReNNnBDiHj6nWA7htbkNZbh"),
Attrs: [464]byte{
AttrsData: [464]byte{
0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x0a,
0x46, 0x58, 0x2e, 0x45, 0x55, 0x52, 0x2f, 0x55,
0x53, 0x44, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74,
Expand All @@ -65,10 +65,9 @@ func TestProductAccount(t *testing.T) {

var actual ProductAccount
require.NoError(t, actual.UnmarshalBinary(caseProductAccount))

assert.Equal(t, &expected, &actual)

t.Run("GetAttrs", func(t *testing.T) {
t.Run("GetAttrsMap", func(t *testing.T) {
expected := map[string]string{
"asset_type": "FX",
"base": "EUR",
Expand All @@ -78,123 +77,124 @@ func TestProductAccount(t *testing.T) {
"symbol": "FX.EUR/USD",
"tenor": "Spot",
}
actual, err := actual.GetAttrs()
actualList, err := actual.GetAttrsMap()
assert.NoError(t, err)
actual := actualList.KVs()
assert.Equal(t, expected, actual)
})
}

func TestPriceAccount(t *testing.T) {
expected := PriceAccount{
AccountHeader: AccountHeader{
Magic: Magic,
Version: V2,
AccountType: AccountTypePrice,
Size: 1200,
var priceAccount_E36MyBbavhYKHVLWR79GiReNNnBDiHj6nWA7htbkNZbh = PriceAccount{
AccountHeader: AccountHeader{
Magic: Magic,
Version: V2,
AccountType: AccountTypePrice,
Size: 1200,
},
PriceType: 1,
Exponent: -5,
Num: 10,
NumQt: 0,
LastSlot: 117136050,
ValidSlot: 117491486,
Twap: Ema{
Val: 112674,
Numer: 5644642336,
Denom: 5009691136,
},
Twac: Ema{
Val: 4,
Numer: 2033641276,
Denom: 5009691136,
},
Drv1: 1,
Drv2: 0,
Product: solana.MustPublicKeyFromBase58("EWxGfxoPQSNA2744AYdAKmsQZ8F9o9M7oKkvL3VM1dko"),
Next: solana.PublicKey{},
PrevSlot: 117491485,
PrevPrice: 112717,
PrevConf: 6,
Drv3: -2413575930482041166,
Agg: PriceInfo{
Price: 112717,
Conf: 6,
Status: 0,
CorpAct: 0,
PubSlot: 117491487,
},
Components: [32]PriceComp{
{
Publisher: solana.MustPublicKeyFromBase58("5U3bH5b6XtG99aVWLqwVzYPVpQiFHytBD68Rz2eFPZd7"),
Agg: PriceInfo{
PubSlot: 117491484,
},
Latest: PriceInfo{
PubSlot: 117491485,
},
},
PriceType: 1,
Exponent: -5,
Num: 10,
NumQt: 0,
LastSlot: 117136050,
ValidSlot: 117491486,
Twap: Ema{
Val: 112674,
Numer: 5644642336,
Denom: 5009691136,
{
Publisher: solana.MustPublicKeyFromBase58("4iVm6RJVU4R6kvc3KUDnE6cw4Ffb6769FzbXMu26sJrs"),
},
Twac: Ema{
Val: 4,
Numer: 2033641276,
Denom: 5009691136,
{
Publisher: solana.MustPublicKeyFromBase58("3djmXHmD9kuAydgFnSnWAjq4Kos5GnEx2KdFR2kvGiUw"),
},
Drv1: 1,
Drv2: 0,
Product: solana.MustPublicKeyFromBase58("EWxGfxoPQSNA2744AYdAKmsQZ8F9o9M7oKkvL3VM1dko"),
Next: solana.PublicKey{},
PrevSlot: 117491485,
PrevPrice: 112717,
PrevConf: 6,
Drv3: -2413575930482041166,
Agg: PriceInfo{
Price: 112717,
Conf: 6,
Status: 0,
CorpAct: 0,
PubSlot: 117491487,
{
Publisher: solana.MustPublicKeyFromBase58("86DsXwBCqFoCUiuB1t9oV2inHKQ5h2vFaNZ4GETvTHuz"),
},
Components: [32]PriceComp{
{
Publisher: solana.MustPublicKeyFromBase58("5U3bH5b6XtG99aVWLqwVzYPVpQiFHytBD68Rz2eFPZd7"),
Agg: PriceInfo{
PubSlot: 117491484,
},
Latest: PriceInfo{
PubSlot: 117491485,
},
},
{
Publisher: solana.MustPublicKeyFromBase58("4iVm6RJVU4R6kvc3KUDnE6cw4Ffb6769FzbXMu26sJrs"),
},
{
Publisher: solana.MustPublicKeyFromBase58("3djmXHmD9kuAydgFnSnWAjq4Kos5GnEx2KdFR2kvGiUw"),
},
{
Publisher: solana.MustPublicKeyFromBase58("86DsXwBCqFoCUiuB1t9oV2inHKQ5h2vFaNZ4GETvTHuz"),
},
{
Publisher: solana.MustPublicKeyFromBase58("rkTtobRtTCDLXbADsbVxHcfBr7Z8Z1JDSBM3kyk3LJe"),
},
{
Publisher: solana.MustPublicKeyFromBase58("2pfE7YYVhM9WaneVVF2kcwArMoconfjtq83oZfSurkkY"),
},
{
Publisher: solana.MustPublicKeyFromBase58("2vTC3XNpi7ED5T643KxVH5HqM7cSRKuUGnmMtKACY4Ju"),
{
Publisher: solana.MustPublicKeyFromBase58("rkTtobRtTCDLXbADsbVxHcfBr7Z8Z1JDSBM3kyk3LJe"),
},
{
Publisher: solana.MustPublicKeyFromBase58("2pfE7YYVhM9WaneVVF2kcwArMoconfjtq83oZfSurkkY"),
},
{
Publisher: solana.MustPublicKeyFromBase58("2vTC3XNpi7ED5T643KxVH5HqM7cSRKuUGnmMtKACY4Ju"),
},
{
Publisher: solana.MustPublicKeyFromBase58("45FYxKkPM1NhavyAHFTyXG2JCSsy5jD1UwwCz5UtHX5y"),
},
{
Publisher: solana.MustPublicKeyFromBase58("EevTjv14eGHqsxKvgpastHsuLr9FNPfzkP23wG61pT2U"),
Agg: PriceInfo{
Price: 113062,
Conf: 1,
Status: 1,
CorpAct: 0,
PubSlot: 116660829,
},
{
Publisher: solana.MustPublicKeyFromBase58("45FYxKkPM1NhavyAHFTyXG2JCSsy5jD1UwwCz5UtHX5y"),
Latest: PriceInfo{
Price: 113062,
Conf: 1,
Status: 1,
CorpAct: 0,
PubSlot: 116660829,
},
{
Publisher: solana.MustPublicKeyFromBase58("EevTjv14eGHqsxKvgpastHsuLr9FNPfzkP23wG61pT2U"),
Agg: PriceInfo{
Price: 113062,
Conf: 1,
Status: 1,
CorpAct: 0,
PubSlot: 116660829,
},
Latest: PriceInfo{
Price: 113062,
Conf: 1,
Status: 1,
CorpAct: 0,
PubSlot: 116660829,
},
},
{
Publisher: solana.MustPublicKeyFromBase58("AKPWGLY5KpxbTx7DaVp4Pve8JweMjKbb1A19MyL2nrYT"),
Agg: PriceInfo{
Price: 111976,
Conf: 16,
Status: 1,
CorpAct: 0,
PubSlot: 116917242,
},
{
Publisher: solana.MustPublicKeyFromBase58("AKPWGLY5KpxbTx7DaVp4Pve8JweMjKbb1A19MyL2nrYT"),
Agg: PriceInfo{
Price: 111976,
Conf: 16,
Status: 1,
CorpAct: 0,
PubSlot: 116917242,
},
Latest: PriceInfo{
Price: 111976,
Conf: 16,
Status: 1,
CorpAct: 0,
PubSlot: 116917242,
},
Latest: PriceInfo{
Price: 111976,
Conf: 16,
Status: 1,
CorpAct: 0,
PubSlot: 116917242,
},
},
}
},
}

func TestPriceAccount(t *testing.T) {
var actual PriceAccount
require.NoError(t, actual.UnmarshalBinary(casePriceAccount))

assert.Equal(t, &expected, &actual)
assert.Equal(t, &priceAccount_E36MyBbavhYKHVLWR79GiReNNnBDiHj6nWA7htbkNZbh, &actual)
}

func TestMappingAccount(t *testing.T) {
Expand Down
Loading