package pancakeswapnft import ( "context" "fmt" "github.com/dustin/go-humanize" "sort" "strconv" "time" "github.com/machinebox/graphql" "github.com/pkg/errors" "github.com/rs/zerolog/log" ) type Transaction struct { Id string `json:"id"` Block string `json:"block"` Timestamp int64 `json:"timestamp,string"` Collection Collection `json:"collection"` Nft Nft `json:"nft"` AskPrice float64 `json:"askPrice,string"` NetPrice float64 `json:"netPrice,string"` Buyer User `json:"buyer"` BuyerUsername string Seller User `json:"seller"` SellerUsername string WithBNB bool `json:"withBNB"` Time time.Time Squad Squad Score float64 Url string TimeDescription string IsMine bool } type TransactionService struct { graphClient *graphql.Client squadservice *SquadService floorService *FloorService profileService *ProfileService bscaddress string } func NewTransactionService(graphClient *graphql.Client, squadservice *SquadService, floorService *FloorService, profileService *ProfileService, bscaddress string) *TransactionService { return &TransactionService{ graphClient: graphClient, squadservice: squadservice, floorService: floorService, profileService: profileService, bscaddress: bscaddress, } } type WhereOptions struct { Collection string `json:"collection,omitempty"` TimestampLte string `json:"timestamp_lte,omitempty"` } func (s *TransactionService) GetLightPageByLimit(ctx context.Context, pagenumber int, limit int, opts WhereOptions) ([]Transaction, error) { req := graphql.NewRequest(` query getNftsMarketData($first: Int, $skip: Int!, $where: Transaction_filter, $orderBy: Transaction_orderBy, $orderDirection: OrderDirection) { transactions(where: $where, first: $first, orderBy: $orderBy, orderDirection: $orderDirection, skip: $skip) { timestamp askPrice netPrice nft { tokenId transactionHistory { timestamp askPrice } } buyer { id } seller { id } } }`) req.Var("first", limit) req.Var("orderBy", "timestamp") req.Var("orderDirection", "desc") req.Var("skip", (pagenumber-1)*1000) req.Var("where", opts) var respData struct { Transactions []*Transaction `json:"transactions"` } if err := s.graphClient.Run(ctx, req, &respData); err != nil { return nil, errors.Wrap(err, "requesting graphql") } for _, transaction := range respData.Transactions { squad, err := s.squadservice.GetSquad(transaction.Nft.TokenID) if err != nil { log.Error().Err(err).Msgf("getting squad for tokenid %d", transaction.Nft.TokenID) continue } transaction.Squad = squad transaction.Score = transaction.Squad.GetScoreByPrice(s.floorService, transaction.AskPrice) transaction.Url = fmt.Sprintf("https://pancakeswap.finance/nfts/collections/%s/%d", opts.Collection, transaction.Nft.TokenID) transaction.Time = time.Unix(transaction.Timestamp, 0) transaction.TimeDescription = humanize.Time(transaction.Time) sort.Slice(transaction.Nft.TransactionHistory, func(i, j int) bool { return transaction.Nft.TransactionHistory[i].Timestamp > transaction.Nft.TransactionHistory[j].Timestamp }) transaction.IsMine = transaction.Buyer.Address == s.bscaddress || transaction.Seller.Address == s.bscaddress transaction.SellerUsername = s.profileService.GetUsername(transaction.Seller.Address) transaction.BuyerUsername = s.profileService.GetUsername(transaction.Buyer.Address) } var res []Transaction for _, transaction := range respData.Transactions { res = append(res, *transaction) } return res, nil } func (s *TransactionService) GetPageByLimit(ctx context.Context, pagenumber int, limit int, opts WhereOptions) ([]Transaction, error) { req := graphql.NewRequest(` query getNftsMarketData($first: Int, $skip: Int!, $where: Transaction_filter, $orderBy: Transaction_orderBy, $orderDirection: OrderDirection) { transactions(where: $where, first: $first, orderBy: $orderBy, orderDirection: $orderDirection, skip: $skip) { id block timestamp askPrice netPrice nft { tokenId } collection { id } buyer { id } seller { id } withBNB } }`) req.Var("first", limit) req.Var("orderBy", "timestamp") req.Var("orderDirection", "desc") req.Var("skip", (pagenumber-1)*1000) req.Var("where", opts) var respData struct { Transactions []*Transaction `json:"transactions"` } if err := s.graphClient.Run(ctx, req, &respData); err != nil { return nil, errors.Wrap(err, "requesting graphql") } for _, transaction := range respData.Transactions { squad, err := s.squadservice.GetSquad(transaction.Nft.TokenID) if err != nil { log.Error().Err(err).Msgf("getting squad for tokenid %d", transaction.Nft.TokenID) continue } transaction.Squad = squad transaction.Score = 10 / ((float64(squad.Rank) / float64(10000)) * transaction.AskPrice) transaction.Url = fmt.Sprintf("https://pancakeswap.finance/nfts/collections/%s/%d", opts.Collection, transaction.Nft.TokenID) transaction.Time = time.Unix(transaction.Timestamp, 0) transaction.TimeDescription = humanize.Time(transaction.Time) transaction.SellerUsername = s.profileService.GetUsername(transaction.Seller.Address) transaction.BuyerUsername = s.profileService.GetUsername(transaction.Buyer.Address) } var res []Transaction for _, transaction := range respData.Transactions { res = append(res, *transaction) } return res, nil } func (s *TransactionService) GetAll(ctx context.Context, collection string) ([]Transaction, error) { var res []Transaction currentpage := 1 whereoptions := WhereOptions{ Collection: collection, TimestampLte: "", } now := time.Now() tmpmap := make(map[string]Transaction) loop: for { log.Debug().Msgf("timestamp : %s", whereoptions.TimestampLte) page, err := s.GetPageByLimit(ctx, currentpage, 1000, whereoptions) if err != nil { return nil, errors.Wrapf(err, "getting page %d", currentpage) } if len(page) == 0 { break } for _, transaction := range page { if transaction.Time.Before(now.Add(-7 * 24 * time.Hour)) { break loop } tmpmap[transaction.Id] = transaction } currentpage++ whereoptions.TimestampLte = strconv.Itoa(int(page[len(page)-1].Timestamp)) } for _, transaction := range tmpmap { res = append(res, transaction) } sort.Slice(res, func(i, j int) bool { return res[i].Timestamp > res[j].Timestamp }) return res, nil }