Commit 18939aa8 authored by Charles Bachmeier's avatar Charles Bachmeier Committed by GitHub

feat: Migrate NFT Activity to GraphQL (#6103)

* add new activity query

* add nftactivity hook and fix query

* converted activity type to accept optionals, hook should return activity type

* single asset activity

* relaystylepagination

* working on local endpoint

* working timestamps

* updated endpoint

* use correct env var

* undo asset testing

* forgot last

* undo more testing

* don't break on null address

* working loading state

* better loading states

* handle marketplace type update

* remove types

* properly format price and reduce redundancy

* handle null price

---------
Co-authored-by: default avatarCharles Bachmeier <charlie@genie.xyz>
parent bc251230
...@@ -19,6 +19,7 @@ export const apolloClient = new ApolloClient({ ...@@ -19,6 +19,7 @@ export const apolloClient = new ApolloClient({
fields: { fields: {
nftBalances: relayStylePagination(), nftBalances: relayStylePagination(),
nftAssets: relayStylePagination(), nftAssets: relayStylePagination(),
nftActivity: relayStylePagination(),
// tell apollo client how to reference Token items in the cache after being fetched by queries that return Token[] // tell apollo client how to reference Token items in the cache after being fetched by queries that return Token[]
token: { token: {
read(_, { args, toReference }): Reference | undefined { read(_, { args, toReference }): Reference | undefined {
......
import { WatchQueryFetchPolicy } from '@apollo/client'
import { useNftGraphqlEnabled } from 'featureFlags/flags/nftlGraphql'
import gql from 'graphql-tag'
import { ActivityEvent } from 'nft/types'
import { useCallback, useMemo } from 'react'
import { NftActivityFilterInput, useNftActivityQuery } from '../__generated__/types-and-hooks'
gql`
query NftActivity($filter: NftActivityFilterInput, $after: String, $first: Int) {
nftActivity(filter: $filter, after: $after, first: $first) {
edges {
node {
id
address
tokenId
asset {
id
metadataUrl
image {
id
url
}
smallImage {
id
url
}
name
rarities {
id
provider
rank
score
}
suspiciousFlag
nftContract {
id
standard
}
collection {
id
image {
id
url
}
}
}
type
marketplace
fromAddress
toAddress
transactionHash
price {
id
value
}
orderStatus
quantity
url
timestamp
}
}
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
}
}
}
`
export function useNftActivity(filter: NftActivityFilterInput, first?: number, fetchPolicy?: WatchQueryFetchPolicy) {
const isNftGraphqlEnabled = useNftGraphqlEnabled()
const { data, loading, fetchMore, error } = useNftActivityQuery({
variables: {
filter,
first,
},
skip: !isNftGraphqlEnabled,
fetchPolicy,
})
const hasNext = data?.nftActivity?.pageInfo?.hasNextPage
const loadMore = useCallback(
() =>
fetchMore({
variables: {
after: data?.nftActivity?.pageInfo?.endCursor,
},
}),
[data, fetchMore]
)
const nftActivity: ActivityEvent[] | undefined = useMemo(
() =>
data?.nftActivity?.edges?.map((queryActivity) => {
const activity = queryActivity?.node
const asset = activity?.asset
return {
collectionAddress: activity.address,
tokenId: activity.tokenId,
tokenMetadata: {
name: asset?.name,
imageUrl: asset?.image?.url,
smallImageUrl: asset?.smallImage?.url,
metadataUrl: asset?.metadataUrl,
rarity: {
primaryProvider: 'Rarity Sniper', // TODO update when backend adds more providers
providers: asset?.rarities?.map((rarity) => {
return {
...rarity,
provider: 'Rarity Sniper',
}
}),
},
suspiciousFlag: asset?.suspiciousFlag,
standard: asset?.nftContract?.standard,
},
eventType: activity.type,
marketplace: activity.marketplace,
fromAddress: activity.fromAddress,
toAddress: activity.toAddress,
transactionHash: activity.transactionHash,
orderStatus: activity.orderStatus,
price: activity.price?.value.toString(),
symbol: asset?.collection?.image?.url,
quantity: activity.quantity,
url: activity.url,
eventTimestamp: activity.timestamp * 1000,
}
}),
[data]
)
return useMemo(
() => ({ nftActivity, hasNext, loadMore, loading, error }),
[hasNext, loadMore, loading, nftActivity, error]
)
}
import { OpacityHoverState } from 'components/Common' import { OpacityHoverState } from 'components/Common'
import { useNftGraphqlEnabled } from 'featureFlags/flags/nftlGraphql'
import { NftActivityType } from 'graphql/data/__generated__/types-and-hooks'
import { useNftActivity } from 'graphql/data/nft/NftActivity'
import { Box } from 'nft/components/Box' import { Box } from 'nft/components/Box'
import { Column, Row } from 'nft/components/Flex' import { Column, Row } from 'nft/components/Flex'
import { themeVars, vars } from 'nft/css/sprinkles.css' import { themeVars, vars } from 'nft/css/sprinkles.css'
...@@ -6,7 +9,7 @@ import { useBag, useIsMobile } from 'nft/hooks' ...@@ -6,7 +9,7 @@ import { useBag, useIsMobile } from 'nft/hooks'
import { ActivityFetcher } from 'nft/queries/genie/ActivityFetcher' import { ActivityFetcher } from 'nft/queries/genie/ActivityFetcher'
import { ActivityEvent, ActivityEventResponse, ActivityEventType } from 'nft/types' import { ActivityEvent, ActivityEventResponse, ActivityEventType } from 'nft/types'
import { fetchPrice } from 'nft/utils/fetchPrice' import { fetchPrice } from 'nft/utils/fetchPrice'
import { useCallback, useEffect, useMemo, useReducer, useState } from 'react' import { useCallback, useEffect, useReducer, useState } from 'react'
import InfiniteScroll from 'react-infinite-scroll-component' import InfiniteScroll from 'react-infinite-scroll-component'
import { useInfiniteQuery } from 'react-query' import { useInfiniteQuery } from 'react-query'
import { useIsDarkMode } from 'state/user/hooks' import { useIsDarkMode } from 'state/user/hooks'
...@@ -63,6 +66,7 @@ export const reduceFilters = (state: typeof initialFilterState, action: { eventT ...@@ -63,6 +66,7 @@ export const reduceFilters = (state: typeof initialFilterState, action: { eventT
const baseHref = (event: ActivityEvent) => `/#/nfts/asset/${event.collectionAddress}/${event.tokenId}?origin=activity` const baseHref = (event: ActivityEvent) => `/#/nfts/asset/${event.collectionAddress}/${event.tokenId}?origin=activity`
export const Activity = ({ contractAddress, rarityVerified, collectionName, chainId }: ActivityProps) => { export const Activity = ({ contractAddress, rarityVerified, collectionName, chainId }: ActivityProps) => {
const isNftGraphqlEnabled = useNftGraphqlEnabled()
const [activeFilters, filtersDispatch] = useReducer(reduceFilters, initialFilterState) const [activeFilters, filtersDispatch] = useReducer(reduceFilters, initialFilterState)
const { const {
...@@ -102,11 +106,33 @@ export const Activity = ({ contractAddress, rarityVerified, collectionName, chai ...@@ -102,11 +106,33 @@ export const Activity = ({ contractAddress, rarityVerified, collectionName, chai
} }
) )
const events = useMemo( const {
() => (isSuccess ? eventsData?.pages.map((page) => page.events).flat() : null), nftActivity: gqlEventsData,
[isSuccess, eventsData] hasNext,
loadMore,
loading,
} = useNftActivity(
{
activityTypes: Object.keys(activeFilters)
.map((key) => key as NftActivityType)
.filter((key) => activeFilters[key]),
address: contractAddress,
},
25
) )
const { events, gatedHasNext, gatedLoadMore, gatedLoading, gatedIsLoadingMore } = {
events: isNftGraphqlEnabled
? gqlEventsData
: isSuccess
? eventsData?.pages.map((page) => page.events).flat()
: undefined,
gatedHasNext: isNftGraphqlEnabled ? hasNext : hasNextPage,
gatedLoadMore: isNftGraphqlEnabled ? loadMore : fetchNextPage,
gatedLoading: isNftGraphqlEnabled ? loading : isLoading,
gatedIsLoadingMore: isNftGraphqlEnabled ? hasNext && gqlEventsData?.length : isFetchingNextPage,
}
const itemsInBag = useBag((state) => state.itemsInBag) const itemsInBag = useBag((state) => state.itemsInBag)
const addAssetsToBag = useBag((state) => state.addAssetsToBag) const addAssetsToBag = useBag((state) => state.addAssetsToBag)
const removeAssetsFromBag = useBag((state) => state.removeAssetsFromBag) const removeAssetsFromBag = useBag((state) => state.removeAssetsFromBag)
...@@ -147,19 +173,29 @@ export const Activity = ({ contractAddress, rarityVerified, collectionName, chai ...@@ -147,19 +173,29 @@ export const Activity = ({ contractAddress, rarityVerified, collectionName, chai
<Filter eventType={ActivityEventType.Sale} /> <Filter eventType={ActivityEventType.Sale} />
<Filter eventType={ActivityEventType.Transfer} /> <Filter eventType={ActivityEventType.Transfer} />
</Row> </Row>
{isLoading && <ActivityLoader />} {gatedLoading ? (
{events && ( <ActivityLoader />
) : (
events && (
<Column marginTop="36"> <Column marginTop="36">
<HeaderRow /> <HeaderRow />
<InfiniteScroll <InfiniteScroll
next={fetchNextPage} next={gatedLoadMore}
hasMore={!!hasNextPage} hasMore={!!gatedHasNext}
loader={isFetchingNextPage ? <ActivityPageLoader rowCount={2} /> : null} loader={gatedIsLoadingMore ? <ActivityPageLoader rowCount={2} /> : null}
dataLength={events?.length ?? 0} dataLength={events?.length ?? 0}
style={{ overflow: 'unset' }} style={{ overflow: 'unset' }}
> >
{events.map((event, i) => ( {events.map(
<Box as="a" data-testid="nft-activity-row" href={baseHref(event)} className={styles.eventRow} key={i}> (event, i) =>
event.eventType && (
<Box
as="a"
data-testid="nft-activity-row"
href={baseHref(event)}
className={styles.eventRow}
key={i}
>
<ItemCell <ItemCell
event={event} event={event}
rarityVerified={rarityVerified} rarityVerified={rarityVerified}
...@@ -189,9 +225,11 @@ export const Activity = ({ contractAddress, rarityVerified, collectionName, chai ...@@ -189,9 +225,11 @@ export const Activity = ({ contractAddress, rarityVerified, collectionName, chai
ethPriceInUSD={ethPriceInUSD} ethPriceInUSD={ethPriceInUSD}
/> />
</Box> </Box>
))} )
)}
</InfiniteScroll> </InfiniteScroll>
</Column> </Column>
)
)} )}
</Box> </Box>
) )
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { OpacityHoverState, ScrollBarStyles } from 'components/Common' import { OpacityHoverState, ScrollBarStyles } from 'components/Common'
import { LoadingBubble } from 'components/Tokens/loading' import { LoadingBubble } from 'components/Tokens/loading'
import { useNftGraphqlEnabled } from 'featureFlags/flags/nftlGraphql'
import { EventCell, MarketplaceIcon } from 'nft/components/collection/ActivityCells' import { EventCell, MarketplaceIcon } from 'nft/components/collection/ActivityCells'
import { ActivityEventResponse } from 'nft/types' import { ActivityEvent } from 'nft/types'
import { shortenAddress } from 'nft/utils/address' import { shortenAddress } from 'nft/utils/address'
import { formatEthPrice } from 'nft/utils/currency' import { formatEth, formatEthPrice } from 'nft/utils/currency'
import { getTimeDifference } from 'nft/utils/date' import { getTimeDifference } from 'nft/utils/date'
import { putCommas } from 'nft/utils/putCommas' import { putCommas } from 'nft/utils/putCommas'
import { ReactNode } from 'react' import { ReactNode } from 'react'
...@@ -147,14 +148,19 @@ export const LoadingAssetActivity = ({ rowCount }: { rowCount: number }) => { ...@@ -147,14 +148,19 @@ export const LoadingAssetActivity = ({ rowCount }: { rowCount: number }) => {
) )
} }
const AssetActivity = ({ eventsData }: { eventsData: ActivityEventResponse | undefined }) => { const AssetActivity = ({ events }: { events: ActivityEvent[] | undefined }) => {
const isNftGraphqlEnabled = useNftGraphqlEnabled()
return ( return (
<ActivityTable> <ActivityTable>
{eventsData?.events && {events &&
eventsData.events.map((event, index) => { events.map((event, index) => {
const { eventTimestamp, eventType, fromAddress, marketplace, price, toAddress, transactionHash } = event const { eventTimestamp, eventType, fromAddress, marketplace, price, toAddress, transactionHash } = event
const formattedPrice = price ? putCommas(formatEthPrice(price)).toString() : null const formattedPrice = price
? isNftGraphqlEnabled
? formatEth(parseFloat(price ?? ''))
: putCommas(formatEthPrice(price)).toString()
: null
if (!eventType) return null
return ( return (
<TR key={index}> <TR key={index}>
<TD> <TD>
...@@ -189,7 +195,7 @@ const AssetActivity = ({ eventsData }: { eventsData: ActivityEventResponse | und ...@@ -189,7 +195,7 @@ const AssetActivity = ({ eventsData }: { eventsData: ActivityEventResponse | und
</Link> </Link>
)} )}
</TD> </TD>
<TD>{eventTimestamp && getTimeDifference(eventTimestamp.toString())}</TD> <TD>{eventTimestamp && getTimeDifference(eventTimestamp.toString(), isNftGraphqlEnabled)}</TD>
</TR> </TR>
) )
})} })}
......
import { OpacityHoverState, ScrollBarStyles } from 'components/Common' import { OpacityHoverState, ScrollBarStyles } from 'components/Common'
import Resource from 'components/Tokens/TokenDetails/Resource' import Resource from 'components/Tokens/TokenDetails/Resource'
import { MouseoverTooltip } from 'components/Tooltip/index' import { MouseoverTooltip } from 'components/Tooltip/index'
import { useNftGraphqlEnabled } from 'featureFlags/flags/nftlGraphql'
import { NftActivityType } from 'graphql/data/__generated__/types-and-hooks'
import { useNftActivity } from 'graphql/data/nft/NftActivity'
import { Box } from 'nft/components/Box' import { Box } from 'nft/components/Box'
import { reduceFilters } from 'nft/components/collection/Activity' import { reduceFilters } from 'nft/components/collection/Activity'
import { LoadingSparkle } from 'nft/components/common/Loading/LoadingSparkle' import { LoadingSparkle } from 'nft/components/common/Loading/LoadingSparkle'
...@@ -10,7 +13,7 @@ import { themeVars, vars } from 'nft/css/sprinkles.css' ...@@ -10,7 +13,7 @@ import { themeVars, vars } from 'nft/css/sprinkles.css'
import { ActivityFetcher } from 'nft/queries/genie/ActivityFetcher' import { ActivityFetcher } from 'nft/queries/genie/ActivityFetcher'
import { ActivityEventResponse, ActivityEventType, CollectionInfoForAsset, GenieAsset } from 'nft/types' import { ActivityEventResponse, ActivityEventType, CollectionInfoForAsset, GenieAsset } from 'nft/types'
import { shortenAddress } from 'nft/utils/address' import { shortenAddress } from 'nft/utils/address'
import { formatEthPrice } from 'nft/utils/currency' import { formatEth, formatEthPrice } from 'nft/utils/currency'
import { isAudio } from 'nft/utils/isAudio' import { isAudio } from 'nft/utils/isAudio'
import { isVideo } from 'nft/utils/isVideo' import { isVideo } from 'nft/utils/isVideo'
import { putCommas } from 'nft/utils/putCommas' import { putCommas } from 'nft/utils/putCommas'
...@@ -244,6 +247,7 @@ interface AssetDetailsProps { ...@@ -244,6 +247,7 @@ interface AssetDetailsProps {
} }
export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => { export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
const isNftGraphqlEnabled = useNftGraphqlEnabled()
const [dominantColor] = useState<[number, number, number]>([0, 0, 0]) const [dominantColor] = useState<[number, number, number]>([0, 0, 0])
const { rarityProvider } = useMemo( const { rarityProvider } = useMemo(
...@@ -299,10 +303,26 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => { ...@@ -299,10 +303,26 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
refetchOnMount: false, refetchOnMount: false,
} }
) )
const { nftActivity: gqlPriceData } = useNftActivity(
{
activityTypes: [NftActivityType.Sale],
address: contractAddress,
tokenId: token_id,
},
1,
'no-cache'
)
const lastSalePrice = priceData?.events[0]?.price ?? null // TODO simplify typecasting when removing graphql flag
const formattedEthprice = formatEthPrice(lastSalePrice ?? '') || 0 const lastSalePrice = isNftGraphqlEnabled ? gqlPriceData?.[0]?.price : priceData?.events[0]?.price
const formattedPrice = lastSalePrice ? putCommas(formattedEthprice).toString() : null const formattedEthprice = isNftGraphqlEnabled
? formatEth(parseFloat(lastSalePrice ?? ''))
: formatEthPrice(lastSalePrice) || 0
const formattedPrice = isNftGraphqlEnabled
? formattedEthprice
: lastSalePrice
? putCommas(parseFloat(formattedEthprice.toString())).toString()
: null
const [activeFilters, filtersDispatch] = useReducer(reduceFilters, initialFilterState) const [activeFilters, filtersDispatch] = useReducer(reduceFilters, initialFilterState)
const Filter = useCallback( const Filter = useCallback(
...@@ -365,13 +385,48 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => { ...@@ -365,13 +385,48 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
} }
) )
const rarity = asset?.rarity?.providers?.length ? asset?.rarity?.providers?.[0] : undefined const {
nftActivity: gqlEventsData,
hasNext,
loadMore,
loading,
error,
} = useNftActivity(
{
activityTypes: Object.keys(activeFilters)
.map((key) => key as NftActivityType)
.filter((key) => activeFilters[key]),
address: contractAddress,
tokenId: token_id,
},
25
)
const { events, gatedHasNext, gatedLoadMore, gatedLoading, gatedSuccess } = useMemo(() => {
return {
events: isNftGraphqlEnabled ? gqlEventsData : eventsData?.pages.map((page) => page.events).flat(),
gatedHasNext: isNftGraphqlEnabled ? hasNext : hasNextPage,
gatedLoadMore: isNftGraphqlEnabled ? loadMore : fetchNextPage,
gatedLoading: isNftGraphqlEnabled ? loading : isActivityLoading,
gatedSuccess: isNftGraphqlEnabled ? !error : isSuccess,
}
}, [
error,
eventsData?.pages,
fetchNextPage,
gqlEventsData,
hasNext,
hasNextPage,
isActivityLoading,
isNftGraphqlEnabled,
isSuccess,
loadMore,
loading,
])
const rarity = asset?.rarity?.providers?.[0]
const [showHolder, setShowHolder] = useState(false) const [showHolder, setShowHolder] = useState(false)
const rarityProviderLogo = getRarityProviderLogo(rarity?.provider) const rarityProviderLogo = getRarityProviderLogo(rarity?.provider)
const events = useMemo(
() => (isSuccess ? eventsData?.pages.map((page) => page.events).flat() : null),
[isSuccess, eventsData]
)
return ( return (
<Column> <Column>
...@@ -433,11 +488,12 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => { ...@@ -433,11 +488,12 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
<Filter eventType={ActivityEventType.Transfer} /> <Filter eventType={ActivityEventType.Transfer} />
<Filter eventType={ActivityEventType.CancelListing} /> <Filter eventType={ActivityEventType.CancelListing} />
</ActivitySelectContainer> </ActivitySelectContainer>
{isActivityLoading && <LoadingAssetActivity rowCount={10} />} {gatedLoading ? (
{events && events.length > 0 ? ( <LoadingAssetActivity rowCount={10} />
) : events && events.length > 0 ? (
<InfiniteScroll <InfiniteScroll
next={fetchNextPage} next={gatedLoadMore}
hasMore={!!hasNextPage} hasMore={!!gatedHasNext}
loader={ loader={
isFetchingNextPage && ( isFetchingNextPage && (
<Center> <Center>
...@@ -448,11 +504,11 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => { ...@@ -448,11 +504,11 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
dataLength={events?.length ?? 0} dataLength={events?.length ?? 0}
scrollableTarget="activityContainer" scrollableTarget="activityContainer"
> >
<AssetActivity eventsData={{ events }} /> <AssetActivity events={events} />
</InfiniteScroll> </InfiniteScroll>
) : ( ) : (
<> <>
{!isActivityLoading && ( {gatedSuccess && events && (
<EmptyActivitiesContainer> <EmptyActivitiesContainer>
<div>No activities yet</div> <div>No activities yet</div>
<Link to={`/nfts/collection/${asset.address}`}>View collection items</Link>{' '} <Link to={`/nfts/collection/${asset.address}`}>View collection items</Link>{' '}
......
import { Markets, TokenType } from '../common' import { NftActivityType, NftStandard, OrderStatus } from 'graphql/data/__generated__/types-and-hooks'
import { Markets, Rarity, TokenType } from '../common'
export interface AssetPayload { export interface AssetPayload {
filters: { filters: {
traits?: Record<string, string[]> traits?: Record<string, string[]>
...@@ -57,13 +59,6 @@ export enum ActivityEventTypeDisplay { ...@@ -57,13 +59,6 @@ export enum ActivityEventTypeDisplay {
'CANCEL_LISTING' = 'Cancellation', 'CANCEL_LISTING' = 'Cancellation',
} }
export enum OrderStatus {
VALID = 'VALID',
EXECUTED = 'EXECUTED',
CANCELLED = 'CANCELLED',
EXPIRED = 'EXPIRED',
}
export interface ActivityFilter { export interface ActivityFilter {
collectionAddress?: string collectionAddress?: string
eventTypes?: ActivityEventType[] eventTypes?: ActivityEventType[]
...@@ -83,31 +78,29 @@ export interface TokenRarity { ...@@ -83,31 +78,29 @@ export interface TokenRarity {
} }
export interface TokenMetadata { export interface TokenMetadata {
name: string name?: string
imageUrl: string imageUrl?: string
smallImageUrl: string smallImageUrl?: string
metadataUrl: string metadataUrl?: string
rarity: TokenRarity rarity?: TokenRarity | Rarity
suspiciousFlag: boolean suspiciousFlag?: boolean
suspiciousFlaggedBy: string standard?: TokenType | NftStandard
standard: TokenType
} }
// TODO when deprecating activity query, remove all outdated types (former in optional fields)
export interface ActivityEvent { export interface ActivityEvent {
collectionAddress: string collectionAddress?: string
tokenId?: string tokenId?: string
tokenMetadata?: TokenMetadata tokenMetadata?: TokenMetadata
eventType: ActivityEventType eventType?: NftActivityType
marketplace?: Markets marketplace?: Markets | string
fromAddress: string fromAddress?: string
toAddress?: string toAddress?: string
transactionHash?: string transactionHash?: string
orderHash?: string
orderStatus?: OrderStatus orderStatus?: OrderStatus
price?: string price?: string
symbol?: string symbol?: string
quantity?: number quantity?: number
auctionType?: string
url?: string url?: string
eventTimestamp?: number eventTimestamp?: number
} }
...@@ -9,7 +9,7 @@ import { isAddress } from '@ethersproject/address' ...@@ -9,7 +9,7 @@ import { isAddress } from '@ethersproject/address'
*/ */
export function shortenAddress(address: string, charsStart = 4, charsEnd?: number): string { export function shortenAddress(address: string, charsStart = 4, charsEnd?: number): string {
const parsed = isAddress(address) const parsed = isAddress(address)
if (!parsed) throw Error(`Invalid 'address' parameter '${address}'.`) if (!parsed) return ''
return `${address.substring(0, charsStart + 2)}...${address.substring(42 - (charsEnd || charsStart))}` return `${address.substring(0, charsStart + 2)}...${address.substring(42 - (charsEnd || charsStart))}`
} }
import { BigNumber } from '@ethersproject/bignumber' import { BigNumber } from '@ethersproject/bignumber'
import { formatEther } from '@ethersproject/units' import { formatEther } from '@ethersproject/units'
import { parseEther } from 'ethers/lib/utils'
import { ActivityEvent, GenieAsset } from 'nft/types' import { ActivityEvent, GenieAsset } from 'nft/types'
export const buildActivityAsset = (event: ActivityEvent, collectionName: string, ethPriceInUSD: number): GenieAsset => { import { formatEth } from './currency'
export const buildActivityAsset = (
event: ActivityEvent,
collectionName: string,
ethPriceInUSD: number,
isNftGraphqlEnabled: boolean
): GenieAsset => {
const assetUsdPrice = event.price const assetUsdPrice = event.price
? formatEther( ? isNftGraphqlEnabled
? formatEth(parseFloat(event.price) * ethPriceInUSD)
: formatEther(
BigNumber.from(event.price) BigNumber.from(event.price)
.mul(BigNumber.from(Math.trunc(ethPriceInUSD * 100))) .mul(BigNumber.from(Math.trunc(ethPriceInUSD * 100)))
.div(100) .div(100)
) )
: '0' : '0'
const weiPrice = isNftGraphqlEnabled ? (event.price ? parseEther(event.price) : '') : event.price
return { return {
address: event.collectionAddress, address: event.collectionAddress,
collectionName, collectionName,
...@@ -23,8 +35,8 @@ export const buildActivityAsset = (event: ActivityEvent, collectionName: string, ...@@ -23,8 +35,8 @@ export const buildActivityAsset = (event: ActivityEvent, collectionName: string,
collectionSymbol: event.symbol, collectionSymbol: event.symbol,
priceInfo: { priceInfo: {
USDPrice: assetUsdPrice, USDPrice: assetUsdPrice,
ETHPrice: event.price, ETHPrice: weiPrice,
basePrice: event.price, basePrice: weiPrice,
baseAsset: 'ETH', baseAsset: 'ETH',
}, },
tokenType: event.tokenMetadata?.standard, tokenType: event.tokenMetadata?.standard,
......
...@@ -3,8 +3,8 @@ export const isValidDate = (date: number): boolean => { ...@@ -3,8 +3,8 @@ export const isValidDate = (date: number): boolean => {
return isNaN(d) ? false : true return isNaN(d) ? false : true
} }
export const getTimeDifference = (eventTimestamp: string) => { export const getTimeDifference = (eventTimestamp: string, isNftGraphqlEnabled: boolean) => {
const date = new Date(eventTimestamp).getTime() const date = isNftGraphqlEnabled ? parseFloat(eventTimestamp) : new Date(eventTimestamp).getTime()
const diff = new Date().getTime() - date const diff = new Date().getTime() - date
const days = Math.floor(diff / (1000 * 60 * 60 * 24)) const days = Math.floor(diff / (1000 * 60 * 60 * 24))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment