github.com/gagliardetto/solana-go@v1.11.0/programs/serum/rpc.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  	"bytes"
    22  	"context"
    23  	"fmt"
    24  
    25  	rice "github.com/GeertJohan/go.rice"
    26  	bin "github.com/gagliardetto/binary"
    27  	"github.com/gagliardetto/solana-go"
    28  	"github.com/gagliardetto/solana-go/rpc"
    29  	"github.com/gagliardetto/solana-go/rpc/ws"
    30  	"go.uber.org/zap"
    31  )
    32  
    33  //go:generate rice embed-go
    34  
    35  // TODO: hit the chain and
    36  func KnownMarket() ([]*MarketMeta, error) {
    37  	box := rice.MustFindBox("data").MustBytes("markets.json")
    38  	if box == nil {
    39  		return nil, fmt.Errorf("unable to retrieve known markets")
    40  	}
    41  
    42  	dec := json.NewDecoder(bytes.NewReader(box))
    43  	var markets []*MarketMeta
    44  	err := dec.Decode(&markets)
    45  	if err != nil {
    46  		return nil, fmt.Errorf("unable to decode known markets: %w", err)
    47  	}
    48  	return markets, nil
    49  }
    50  
    51  func FetchOpenOrders(ctx context.Context, rpcCli *rpc.Client, openOrdersAddr solana.PublicKey) (*OpenOrdersMeta, error) {
    52  	acctInfo, err := rpcCli.GetAccountInfo(ctx, openOrdersAddr)
    53  	if err != nil {
    54  		return nil, fmt.Errorf("unable to get open orders account:%w", err)
    55  	}
    56  
    57  	openOrdersMeta := &OpenOrdersMeta{}
    58  
    59  	if err := openOrdersMeta.OpenOrders.Decode(acctInfo.Value.Data.GetBinary()); err != nil {
    60  		return nil, fmt.Errorf("decoding market v2: %w", err)
    61  	}
    62  
    63  	return openOrdersMeta, nil
    64  }
    65  
    66  func FetchMarket(ctx context.Context, rpcCli *rpc.Client, marketAddr solana.PublicKey) (*MarketMeta, error) {
    67  	acctInfo, err := rpcCli.GetAccountInfo(ctx, marketAddr)
    68  	if err != nil {
    69  		return nil, fmt.Errorf("unable to get market account:%w", err)
    70  	}
    71  
    72  	meta := &MarketMeta{
    73  		Address: marketAddr,
    74  	}
    75  
    76  	dataLen := len(acctInfo.Value.Data.GetBinary())
    77  	switch dataLen {
    78  	// case 380:
    79  	// 	// if err := meta.MarketV1.Decode(acctInfo.Value.Data); err != nil {
    80  	// 	// 	return nil, fmt.Errorf("decoding market v1: %w", err)
    81  	// 	// }
    82  	// 	return nil, fmt.Errorf("Unsupported market version, w/ data length of 380")
    83  
    84  	case 388:
    85  		if err := meta.MarketV2.Decode(acctInfo.Value.Data.GetBinary()); err != nil {
    86  			return nil, fmt.Errorf("decoding market v2: %w", err)
    87  		}
    88  
    89  	default:
    90  		return nil, fmt.Errorf("unsupported market data length: %d", dataLen)
    91  	}
    92  
    93  	if err := rpcCli.GetAccountDataInto(ctx, meta.MarketV2.QuoteMint, &meta.QuoteMint); err != nil {
    94  		return nil, fmt.Errorf("getting quote mint: %w", err)
    95  	}
    96  
    97  	if err := rpcCli.GetAccountDataInto(ctx, meta.MarketV2.BaseMint, &meta.BaseMint); err != nil {
    98  		return nil, fmt.Errorf("getting base token: %w", err)
    99  	}
   100  
   101  	return meta, nil
   102  }
   103  
   104  func StreamOpenOrders(client *ws.Client) error {
   105  	sub, err := client.ProgramSubscribe(DEXProgramIDV2, rpc.CommitmentSingleGossip)
   106  	if err != nil {
   107  		return fmt.Errorf("unable to subscribe to programID %q: %w", DEXProgramIDV2, err)
   108  	}
   109  	count := 0
   110  	for {
   111  		d, err := sub.Recv()
   112  		if err != nil {
   113  			return fmt.Errorf("received error from programID subscription: %w", err)
   114  		}
   115  		res := d
   116  
   117  		var f *AccountFlag
   118  		err = bin.NewBinDecoder(res.Value.Account.Data.GetBinary()).Decode(&f)
   119  		if err != nil {
   120  			fmt.Println("***********************************", err)
   121  			zlog.Debug("unable to decoce account flag for account... skipping",
   122  				zap.Stringer("account_address", res.Value.Pubkey),
   123  			)
   124  			continue
   125  		}
   126  		fmt.Printf("%d - %s\n", count, f.String())
   127  		count++
   128  	}
   129  }