pancakeswapnft/transaction.go

218 lines
6.2 KiB
Go

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
}
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)
}
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
}