Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(1115): flipping nfts #88

Closed
wants to merge 11 commits into from
44 changes: 44 additions & 0 deletions src/server-extension/model/nft.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Field, ObjectType } from 'type-graphql';

@ObjectType()
export class FlippingNFT {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may a bit better name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should change all those Flipping to MostTraded?

@Field(() => String, { nullable: false, name: 'nftId' })
nft_id!: string

@Field(() => String, { nullable: false, name: 'collectionId' })
collection_id!: string

@Field(() => String, { nullable: false })
author!: string

@Field(() => Date, { nullable: false })
date!: Date

@Field(() => String)
previous!: string

@Field(() => String, { nullable: false })
current!: string

@Field(() => BigInt, { nullable: true, defaultValue: 0n, name: 'floorPrice' })
floor_price!: bigint

@Field(() => Number, { name: 'previousOwner' })
previous_owners!: number

@Field(() => Number, { nullable: false })
total!: number

@Field(() => Number, { nullable: false, name: 'owners' })
unique_collectors!: number

@Field(() => String, { nullable: false })
distribution!: string

@Field(() => BigInt, { name: 'emotes' })
emote_count!: number

constructor(props: Partial<FlippingNFT>) {
Object.assign(this, props);
}
}
8 changes: 8 additions & 0 deletions src/server-extension/query/collection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const collectionsDistribution = (idList: string): string =>
`SELECT ce.id,
COUNT(ne.current_owner) AS owners,
COUNT (DISTINCT ne.current_owner) AS unique_owner
FROM collection_entity ce
LEFT JOIN nft_entity ne ON ne.collection_id = ce.id
WHERE ce.id in (${idList})
GROUP BY ce.id`
56 changes: 55 additions & 1 deletion src/server-extension/query/nft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,60 @@ FROM nft_entity ne
WHERE ne.current_owner = $1
AND ne.current_owner != ne.issuer`


export const flippingQuery = `SELECT
KngZhi marked this conversation as resolved.
Show resolved Hide resolved
ne.issuer AS author,
e.nft_id,
ne.created_at AS date,
ne.price AS current,
COUNT(e.*) AS total_flip,
COUNT(DISTINCT e.current_owner) AS previous_owners,
s.floor_price,
s.id as collection_id,
s.total,
s.unique_collectors,
s.emote_count
FROM
event e
LEFT JOIN nft_entity ne ON e.nft_id = ne.id
LEFT JOIN series s ON s.id = ne.collection_id
WHERE
e.interaction = 'BUY'
AND ne.burned = 'false'
GROUP BY
author,
e.nft_id,
date,
current,
floor_price,
s.id,
s.total,
s.unique_collectors,
s.emote_count
ORDER BY total_flip DESC
LIMIT $1
OFFSET $2`

export const previousPriceQuery = (idList: string) => `WITH ranking AS (
SELECT
nft_id,
meta,
Rank() OVER (
partition BY nft_id
ORDER BY
e.timestamp DESC
) AS rank
FROM
event e
WHERE
e.nft_id IN (${idList})
)
SELECT
*
FROM
ranking
WHERE
rank IN (2);`
export const salesQuery = `SELECT
ne.id,
ne.name,
Expand All @@ -21,4 +75,4 @@ FROM nft_entity ne
where
e.interaction = 'BUY'
and e.timestamp >= NOW() - INTERVAL '7 DAY'
ORDER BY e.timestamp desc`
ORDER BY e.timestamp desc`
59 changes: 59 additions & 0 deletions src/server-extension/resolvers/flippingNfts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Query, Resolver, Arg } from 'type-graphql'
import type { EntityManager } from 'typeorm'
import { NFTEntity } from '../../model/generated'
import { FlippingNFT } from '../model/nft.model'
import { flippingQuery, previousPriceQuery } from "../query/nft";
import { collectionsDistribution } from "../query/collection"
import { makeQuery, toSqlInParams } from "../utils";

type PreviousNft = {
nft_id: string,
meta: string,
rank: number,
}

type CollectionDistribution = {
id: string
owners: number
unique_owner: number
}

@Resolver()
export class FlippingNFTsResolver {
constructor(private tx: () => Promise<EntityManager>) { }

@Query(() => [FlippingNFT])
async flippingNFTs(
@Arg('limit', { nullable: true, defaultValue: 20 }) limit: number,
@Arg('offset', { nullable: true, defaultValue: 0 }) offset: number,
): Promise<Array<FlippingNFT>> {
const result: Array<FlippingNFT> = await makeQuery(this.tx, NFTEntity, flippingQuery, [limit, offset])

const nfts = result.map(item => item.nft_id)

const prevNFTs: [PreviousNft] = (await makeQuery(
this.tx,
NFTEntity,
previousPriceQuery(toSqlInParams(nfts))))

const collections: CollectionDistribution[] = await makeQuery(
this.tx,
NFTEntity,
collectionsDistribution(toSqlInParams(result.map(item => item.collection_id))))

return result.map(nft => {
const { nft_id, collection_id } = nft
const previousNft = prevNFTs.find((nft) => nft.nft_id === nft_id) || { meta: "0" }
// handle LIST meta is not money
const previous = Number(previousNft.meta)
const { owners = 0, unique_owner = 0} = collections.find(col => col.id === collection_id) || {}

return {
...nft,
previous: Number.isNaN(previous) ? "0" : String(previous),
distribution: (owners / unique_owner).toFixed(2),
}

})
}
}
3 changes: 3 additions & 0 deletions src/server-extension/resolvers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { SpotlightResolver } from './spotlight'
import { CollectionChartResolver } from './collectionChart'
import { CollectionEventResolver } from './collectionEvent'
import { PassionFeedResolver } from "./passionFeed";
import { FlippingNFTsResolver } from "./flippingNfts";
import { SalesFeedResolver } from "./salesFeed";


@ObjectType()
export class Hello {
@Field(() => String, { nullable: false })
Expand Down Expand Up @@ -38,5 +40,6 @@ export {
SpotlightResolver,
CollectionEventResolver,
PassionFeedResolver,
FlippingNFTsResolver,
SalesFeedResolver,
}