diff --git a/pkg/api/account_handlers.go b/pkg/api/account_handlers.go index 92f07f7f..d73e161b 100644 --- a/pkg/api/account_handlers.go +++ b/pkg/api/account_handlers.go @@ -8,9 +8,12 @@ import ( "encoding/json" "errors" "fmt" + "github.com/labstack/gommon/log" + "go.uber.org/zap" "net/http" "sort" "strings" + "sync" "time" "github.com/tonkeeper/opentonapi/pkg/addressbook" @@ -330,10 +333,22 @@ func (h *Handler) GetAccountDnsExpiring(ctx context.Context, params oas.GetAccou accounts = append(accounts, dns.DnsItem.Address) } } + var wg sync.WaitGroup + wg.Add(1) + var nftsScamData map[ton.AccountID]core.TrustType + go func() { + defer wg.Done() + nftsScamData, err = h.spamFilter.GetNftsScamData(ctx, accounts) + if err != nil { + log.Warn("error getting nft scam data", zap.Error(err)) + } + }() nfts, err := h.storage.GetNFTs(ctx, accounts) + wg.Wait() if err != nil { return nil, toError(http.StatusInternalServerError, err) } + for _, dns := range dnsExpiring { dei := oas.DnsExpiringItemsItem{ Name: dns.Name, @@ -342,7 +357,7 @@ func (h *Handler) GetAccountDnsExpiring(ctx context.Context, params oas.GetAccou if dns.DnsItem != nil { for _, n := range nfts { if n.Address == dns.DnsItem.Address { - dei.DNSItem = oas.NewOptNftItem(h.convertNFT(ctx, n, h.addressBook, h.metaCache)) + dei.DNSItem = oas.NewOptNftItem(h.convertNFT(ctx, n, h.addressBook, h.metaCache, nftsScamData[n.Address])) break } } @@ -454,7 +469,12 @@ func (h *Handler) GetAccountNftHistory(ctx context.Context, params oas.GetAccoun if err != nil { return nil, toError(http.StatusInternalServerError, err) } - events, lastLT, err := h.convertNftHistory(ctx, account.ID, traceIDs, params.AcceptLanguage) + var eventIDs []string + for _, traceID := range traceIDs { + eventIDs = append(eventIDs, traceID.Hex()) + } + isBannedTraces, err := h.spamFilter.GetEventsScamData(ctx, eventIDs) + events, lastLT, err := h.convertNftHistory(ctx, account.ID, traceIDs, isBannedTraces, params.AcceptLanguage) if err != nil { return nil, toError(http.StatusInternalServerError, err) } @@ -604,7 +624,3 @@ func (h *Handler) AddressParse(ctx context.Context, params oas.AddressParseParam } return &res, nil //todo: add testnet_only } - -func (h *Handler) GetAccountExtraCurrencyHistoryByID(ctx context.Context, params oas.GetAccountExtraCurrencyHistoryByIDParams) (*oas.AccountEvents, error) { - return &oas.AccountEvents{}, nil -} diff --git a/pkg/api/dns_handlers.go b/pkg/api/dns_handlers.go index f718bcef..e5c5869b 100644 --- a/pkg/api/dns_handlers.go +++ b/pkg/api/dns_handlers.go @@ -149,7 +149,8 @@ func (h *Handler) GetDnsInfo(ctx context.Context, params oas.GetDnsInfoParams) ( convertedDomainInfo := oas.DomainInfo{ Name: params.DomainName, } - convertedDomainInfo.Item.SetTo(h.convertNFT(ctx, nft, h.addressBook, h.metaCache)) + nftScamData, err := h.spamFilter.GetNftsScamData(ctx, []ton.AccountID{nft.Address}) + convertedDomainInfo.Item.SetTo(h.convertNFT(ctx, nft, h.addressBook, h.metaCache, nftScamData[nft.Address])) if expTime != 0 { convertedDomainInfo.ExpiringAt.SetTo(expTime) } diff --git a/pkg/api/event_converters.go b/pkg/api/event_converters.go index 7085f8eb..750d233d 100644 --- a/pkg/api/event_converters.go +++ b/pkg/api/event_converters.go @@ -4,9 +4,12 @@ import ( "context" "encoding/hex" "fmt" + "github.com/labstack/gommon/log" + "go.uber.org/zap" "math/big" "sort" "strings" + "sync" "github.com/tonkeeper/tongo/ton" @@ -84,12 +87,24 @@ func (h *Handler) convertRisk(ctx context.Context, risk wallet.Risk, walletAddre oasRisk.Jettons = append(oasRisk.Jettons, jettonQuantity) } if len(risk.Nfts) > 0 { + var wg sync.WaitGroup + wg.Add(1) + var nftsScamData map[ton.AccountID]core.TrustType + var err error + go func() { + defer wg.Done() + nftsScamData, err = h.spamFilter.GetNftsScamData(ctx, risk.Nfts) + if err != nil { + log.Warn("error getting nft scam data", zap.Error(err)) + } + }() items, err := h.storage.GetNFTs(ctx, risk.Nfts) + wg.Wait() if err != nil { return oas.Risk{}, err } for _, item := range items { - nft := h.convertNFT(ctx, item, h.addressBook, h.metaCache) + nft := h.convertNFT(ctx, item, h.addressBook, h.metaCache, nftsScamData[item.Address]) oasRisk.Nfts = append(oasRisk.Nfts, nft) } } @@ -562,7 +577,7 @@ func (h *Handler) convertAction(ctx context.Context, viewer *tongo.AccountID, a var name string if len(items) == 1 { // opentonapi doesn't implement GetNFTs() now - nft = h.convertNFT(ctx, items[0], h.addressBook, h.metaCache) + nft = h.convertNFT(ctx, items[0], h.addressBook, h.metaCache, "") if len(nft.Previews) > 0 { nftImage = nft.Previews[0].URL } @@ -700,7 +715,7 @@ func (h *Handler) convertAction(ctx context.Context, viewer *tongo.AccountID, a if a.AuctionBid.Nft == nil { return oas.Action{}, fmt.Errorf("nft is nil") } - nft.SetTo(h.convertNFT(ctx, *a.AuctionBid.Nft, h.addressBook, h.metaCache)) + nft.SetTo(h.convertNFT(ctx, *a.AuctionBid.Nft, h.addressBook, h.metaCache, "")) action.AuctionBid.SetTo(oas.AuctionBidAction{ Amount: oas.Price{ Value: fmt.Sprintf("%v", a.AuctionBid.Amount), diff --git a/pkg/api/interfaces.go b/pkg/api/interfaces.go index 09b952a6..85e6d8ef 100644 --- a/pkg/api/interfaces.go +++ b/pkg/api/interfaces.go @@ -188,7 +188,8 @@ type SpamFilter interface { GetEventsScamData(ctx context.Context, ids []string) (map[string]bool, error) JettonTrust(address tongo.AccountID, symbol, name, image string) core.TrustType AccountTrust(address tongo.AccountID) core.TrustType - NftTrust(ctx context.Context, address tongo.AccountID, collection *ton.AccountID, description, image string) core.TrustType + NftTrust(address tongo.AccountID, collection *ton.AccountID, description, image string) core.TrustType + GetNftsScamData(ctx context.Context, addresses []ton.AccountID) (map[ton.AccountID]core.TrustType, error) } type verifierSource interface { diff --git a/pkg/api/nft_converters.go b/pkg/api/nft_converters.go index f8f37e7d..e369b27e 100644 --- a/pkg/api/nft_converters.go +++ b/pkg/api/nft_converters.go @@ -17,7 +17,7 @@ import ( "github.com/tonkeeper/opentonapi/pkg/references" ) -func (h *Handler) convertNFT(ctx context.Context, item core.NftItem, book addressBook, metaCache metadataCache) oas.NftItem { +func (h *Handler) convertNFT(ctx context.Context, item core.NftItem, book addressBook, metaCache metadataCache, trustType core.TrustType) oas.NftItem { nftItem := oas.NftItem{ Address: item.Address.ToRaw(), Index: item.Index.BigInt().Int64(), @@ -77,7 +77,11 @@ func (h *Handler) convertNFT(ctx context.Context, item core.NftItem, book addres if len(nftItem.ApprovedBy) > 0 && nftItem.Verified { nftItem.Trust = oas.TrustType(core.TrustWhitelist) } else { - nftItem.Trust = oas.TrustType(h.spamFilter.NftTrust(ctx, item.Address, item.CollectionAddress, description, image)) + nftTrust := h.spamFilter.NftTrust(item.Address, item.CollectionAddress, description, image) + if nftTrust == core.TrustNone && trustType != "" { + nftTrust = trustType + } + nftItem.Trust = oas.TrustType(nftTrust) } if image == "" { image = references.Placeholder diff --git a/pkg/api/nft_handlers.go b/pkg/api/nft_handlers.go index 70bc6083..3d028569 100644 --- a/pkg/api/nft_handlers.go +++ b/pkg/api/nft_handlers.go @@ -4,7 +4,10 @@ import ( "context" "errors" "fmt" + "github.com/labstack/gommon/log" + "github.com/tonkeeper/tongo/ton" "net/http" + "sync" "go.uber.org/zap" @@ -31,7 +34,19 @@ func (h *Handler) GetNftItemsByAddresses(ctx context.Context, request oas.OptGet } accounts[i] = account.ID } + var wg sync.WaitGroup + wg.Add(1) + var nftsScamData map[ton.AccountID]core.TrustType + go func() { + defer wg.Done() + var err error + nftsScamData, err = h.spamFilter.GetNftsScamData(ctx, accounts) + if err != nil { + log.Warn("error getting nft scam data", zap.Error(err)) + } + }() items, err := h.storage.GetNFTs(ctx, accounts) + wg.Wait() if errors.Is(err, core.ErrEntityNotFound) { return nil, toError(http.StatusNotFound, err) } @@ -40,7 +55,7 @@ func (h *Handler) GetNftItemsByAddresses(ctx context.Context, request oas.OptGet } var result oas.NftItems for _, i := range items { - result.NftItems = append(result.NftItems, h.convertNFT(ctx, i, h.addressBook, h.metaCache)) + result.NftItems = append(result.NftItems, h.convertNFT(ctx, i, h.addressBook, h.metaCache, nftsScamData[i.Address])) } return &result, nil } @@ -57,7 +72,8 @@ func (h *Handler) GetNftItemByAddress(ctx context.Context, params oas.GetNftItem if len(items) != 1 { return nil, toError(http.StatusNotFound, fmt.Errorf("item not found")) } - result := h.convertNFT(ctx, items[0], h.addressBook, h.metaCache) + nftScamData, err := h.spamFilter.GetNftsScamData(ctx, []ton.AccountID{account.ID}) + result := h.convertNFT(ctx, items[0], h.addressBook, h.metaCache, nftScamData[account.ID]) return &result, nil } @@ -92,7 +108,19 @@ func (h *Handler) GetAccountNftItems(ctx context.Context, params oas.GetAccountN if len(ids) == 0 { return &result, nil } + var wg sync.WaitGroup + wg.Add(1) + var nftsScamData map[ton.AccountID]core.TrustType + go func() { + defer wg.Done() + var err error + nftsScamData, err = h.spamFilter.GetNftsScamData(ctx, ids) + if err != nil { + log.Warn("error getting nft scam data", zap.Error(err)) + } + }() items, err := h.storage.GetNFTs(ctx, ids) + wg.Wait() if err != nil { return nil, toError(http.StatusInternalServerError, err) } @@ -101,7 +129,7 @@ func (h *Handler) GetAccountNftItems(ctx context.Context, params oas.GetAccountN zap.Int("offset", params.Offset.Value), zap.Int("items", len(items))) for _, i := range items { - result.NftItems = append(result.NftItems, h.convertNFT(ctx, i, h.addressBook, h.metaCache)) + result.NftItems = append(result.NftItems, h.convertNFT(ctx, i, h.addressBook, h.metaCache, nftsScamData[i.Address])) } return &result, nil } @@ -147,7 +175,19 @@ func (h *Handler) GetItemsFromCollection(ctx context.Context, params oas.GetItem if len(ids) == 0 { return &result, nil } + var wg sync.WaitGroup + wg.Add(1) + var nftsScamData map[ton.AccountID]core.TrustType + go func() { + defer wg.Done() + var err error + nftsScamData, err = h.spamFilter.GetNftsScamData(ctx, ids) + if err != nil { + log.Warn("error getting nft scam data", zap.Error(err)) + } + }() items, err := h.storage.GetNFTs(ctx, ids) + wg.Wait() if err != nil { return nil, toError(http.StatusInternalServerError, err) } @@ -156,7 +196,7 @@ func (h *Handler) GetItemsFromCollection(ctx context.Context, params oas.GetItem return a.Index.Cmp(b.Index) }) for _, i := range items { - result.NftItems = append(result.NftItems, h.convertNFT(ctx, i, h.addressBook, h.metaCache)) + result.NftItems = append(result.NftItems, h.convertNFT(ctx, i, h.addressBook, h.metaCache, nftsScamData[i.Address])) } return &result, nil } diff --git a/pkg/spam/spam.go b/pkg/spam/spam.go index de05f6d7..3b58787e 100644 --- a/pkg/spam/spam.go +++ b/pkg/spam/spam.go @@ -19,6 +19,10 @@ func NewSpamFilter() *Filter { } } +func (f *Filter) GetNftsScamData(ctx context.Context, addresses []ton.AccountID) (map[ton.AccountID]core.TrustType, error) { + return nil, nil +} + func (f *Filter) GetEventsScamData(ctx context.Context, ids []string) (map[string]bool, error) { return nil, nil } @@ -54,7 +58,7 @@ func (f Filter) JettonTrust(address tongo.AccountID, symbol, name, image string) return core.TrustNone } -func (f Filter) NftTrust(ctx context.Context, address tongo.AccountID, collection *ton.AccountID, description, image string) core.TrustType { +func (f Filter) NftTrust(address tongo.AccountID, collection *ton.AccountID, description, image string) core.TrustType { return core.TrustNone }