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 }