github.com/stellar/stellar-etl@v1.0.1-0.20240312145900-4874b6bf2b89/internal/input/trades.go (about)

     1  package input
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"time"
     7  
     8  	"github.com/stellar/stellar-etl/internal/toid"
     9  	"github.com/stellar/stellar-etl/internal/utils"
    10  
    11  	"github.com/stellar/go/ingest"
    12  	"github.com/stellar/go/ingest/ledgerbackend"
    13  	"github.com/stellar/go/xdr"
    14  )
    15  
    16  // TradeTransformInput is a representation of the input for the TransformTrade function
    17  type TradeTransformInput struct {
    18  	OperationIndex     int32
    19  	Transaction        ingest.LedgerTransaction
    20  	CloseTime          time.Time
    21  	OperationHistoryID int64
    22  }
    23  
    24  // GetTrades returns a slice of trades for the ledgers in the provided range (inclusive on both ends)
    25  func GetTrades(start, end uint32, limit int64, env utils.EnvironmentDetails) ([]TradeTransformInput, error) {
    26  	ctx := context.Background()
    27  
    28  	backend, err := env.CreateCaptiveCoreBackend()
    29  
    30  	tradeSlice := []TradeTransformInput{}
    31  	err = backend.PrepareRange(ctx, ledgerbackend.BoundedRange(start, end))
    32  	panicIf(err)
    33  	for seq := start; seq <= end; seq++ {
    34  		changeReader, err := ingest.NewLedgerChangeReader(ctx, backend, env.NetworkPassphrase, seq)
    35  		if err != nil {
    36  			return []TradeTransformInput{}, err
    37  		}
    38  		txReader := changeReader.LedgerTransactionReader
    39  
    40  		closeTime, err := utils.TimePointToUTCTimeStamp(txReader.GetHeader().Header.ScpValue.CloseTime)
    41  		if err != nil {
    42  			return []TradeTransformInput{}, err
    43  		}
    44  
    45  		for int64(len(tradeSlice)) < limit || limit < 0 {
    46  			tx, err := txReader.Read()
    47  			if err == io.EOF {
    48  				break
    49  			}
    50  
    51  			for index, op := range tx.Envelope.Operations() {
    52  				/*
    53  					Trades occur on these operation types:
    54  					manage buy offer, manage sell offer, create passive sell offer, path payment send, and path payment receive
    55  					Not all of these operations will result in trades, but this is checked in TransformTrade (an empty slice is returned if no trades occurred)
    56  
    57  					Trades also can only occur when these operations are successful
    58  				*/
    59  				if operationResultsInTrade(op) && tx.Result.Successful() {
    60  					tradeSlice = append(tradeSlice, TradeTransformInput{
    61  						OperationIndex:     int32(index),
    62  						Transaction:        tx,
    63  						CloseTime:          closeTime,
    64  						OperationHistoryID: toid.New(int32(seq), int32(tx.Index), int32(index)).ToInt64(),
    65  					})
    66  				}
    67  
    68  				if int64(len(tradeSlice)) >= limit && limit >= 0 {
    69  					break
    70  				}
    71  			}
    72  		}
    73  
    74  		txReader.Close()
    75  		if int64(len(tradeSlice)) >= limit && limit >= 0 {
    76  			break
    77  		}
    78  	}
    79  
    80  	return tradeSlice, nil
    81  }
    82  
    83  // operationResultsInTrade returns true if the operation results in a trade
    84  func operationResultsInTrade(operation xdr.Operation) bool {
    85  	switch operation.Body.Type {
    86  	case xdr.OperationTypeManageBuyOffer:
    87  		return true
    88  	case xdr.OperationTypeManageSellOffer:
    89  		return true
    90  	case xdr.OperationTypeCreatePassiveSellOffer:
    91  		return true
    92  	case xdr.OperationTypePathPaymentStrictReceive:
    93  		return true
    94  	case xdr.OperationTypePathPaymentStrictSend:
    95  		return true
    96  	default:
    97  		return false
    98  	}
    99  }