Skip to content

Commit

Permalink
New query
Browse files Browse the repository at this point in the history
  • Loading branch information
ikprk committed Jun 11, 2024
1 parent d65135f commit 83c7b4d
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 2 deletions.
146 changes: 145 additions & 1 deletion src/server-extension/resolvers/CreatorToken/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import { Args, Query, Resolver } from 'type-graphql'
import { Args, Ctx, Info, Query, Resolver } from 'type-graphql'
import { EntityManager } from 'typeorm'
import { CreatorToken, RevenueShare, TokenAccount } from '../../../model'
import { model } from '../model'
import { GraphQLResolveInfo } from 'graphql'
import { computeTransferrableAmount } from './services'
import { ListQuery } from '@subsquid/openreader/lib/sql/query'
import {
GetAccountTransferrableBalanceArgs,
GetAccountTransferrableBalanceResult,
GetCumulativeHistoricalShareAllocationArgs,
GetCumulativeHistoricalShareAllocationResult,
GetShareDividendsResult,
GetShareDividensArgs,
MarketplaceTokensArgs,
CreatorToken as TokenReturnType,
MarketplaceTokensReturnType,
} from './types'
import { getResolveTree } from '@subsquid/openreader/lib/util/resolve-tree'
import { parseAnyTree, parseSqlArguments } from '@subsquid/openreader/lib/opencrud/tree'
import { extendClause } from '../../../utils/sql'
import { Context } from '../../check'
import { getCurrentBlockHeight } from '../../../utils/blockHeight'

export const BLOCKS_PER_DAY = 10 * 60 * 24 // 10 blocs per minute, 60 mins * 24 hours

@Resolver()
export class TokenResolver {
Expand Down Expand Up @@ -41,6 +54,137 @@ export class TokenResolver {
}
}

@Query(() => [MarketplaceTokensReturnType])
async getMarketplaceTokens(
@Args() args: MarketplaceTokensArgs,
@Info() info: GraphQLResolveInfo,
@Ctx() ctx: Context
) {
const em = await this.em()
const { lastProcessedBlock } = await getCurrentBlockHeight(em)

if (lastProcessedBlock < 0) {
throw new Error('Failed to retrieve processor block height')
}

const tree = getResolveTree(info)
const sqlArgs = parseSqlArguments(model, 'CreatorToken', {
where: args.where,
})

const tokenSubTree = tree.fieldsByTypeName.MarketplaceTokensReturnType.creatorToken
const tokenFields = parseAnyTree(model, 'CreatorToken', info.schema, tokenSubTree)

const topTokensCtes = `
WITH recent_transactions AS (
SELECT
tr.amm_id,
ac.token_id,
ROUND(tr.price_paid / tr.quantity) AS price_paid,
tr.created_in
FROM amm_transaction tr
JOIN amm_curve ac ON tr.amm_id = ac.id
WHERE tr.created_in >= ${lastProcessedBlock - args.periodDays * BLOCKS_PER_DAY}
),
oldest_transactions AS (
SELECT
tr.token_id,
tr.price_paid AS oldest_price_paid
FROM recent_transactions tr
JOIN (
SELECT token_id, MIN(created_in) AS oldest_created_in
FROM recent_transactions
GROUP BY token_id
) oldest ON tr.token_id = oldest.token_id AND tr.created_in = oldest.oldest_created_in
),
newest_transactions AS (
SELECT
tr.token_id,
tr.price_paid AS newest_price_paid
FROM recent_transactions tr
JOIN (
SELECT token_id, MAX(created_in) AS newest_created_in
FROM recent_transactions
GROUP BY token_id
) newest ON tr.token_id = newest.token_id AND tr.created_in = newest.newest_created_in
),
price_changes AS (
SELECT
ot.token_id,
ot.oldest_price_paid,
nt.newest_price_paid,
CASE
WHEN ot.oldest_price_paid = 0 THEN 0
ELSE ((nt.newest_price_paid - ot.oldest_price_paid) * 100.0 / ot.oldest_price_paid)
END AS percentage_change
FROM oldest_transactions ot
JOIN newest_transactions nt ON ot.token_id = nt.token_id
),
ranked_tokens AS (
SELECT token_id, percentage_change, newest_price_paid, oldest_price_paid,
ROW_NUMBER() OVER (ORDER BY percentage_change DESC) AS growth_rank,
ROW_NUMBER() OVER (ORDER BY percentage_change ASC) AS shrink_rank
FROM price_changes
),
top_tokens AS (
SELECT *
FROM ranked_tokens
WHERE growth_rank <= 10 OR shrink_rank <= 10
)
`

const listQuery = new ListQuery(
model,
ctx.openreader.dialect,
'CreatorToken',
tokenFields,
sqlArgs
)

let listQuerySql = listQuery.sql

listQuerySql = extendClause(
listQuerySql,
'SELECT',
'tT.percentage_change as pricePercentageChange'
)

listQuerySql = extendClause(
listQuerySql,
'FROM',
'LEFT JOIN top_tokens tT ON creator_token.id = tT.token_id',
''
)

listQuerySql = extendClause(
listQuerySql,
'WHERE',
'tT.growth_rank <= 10 OR tT.shrink_rank <= 10',
'AND'
)

listQuerySql = `${topTokensCtes} ${listQuerySql}`
;(listQuery as { sql: string }).sql = listQuerySql

const oldListQMap = listQuery.map.bind(listQuery)
listQuery.map = (rows: unknown[][]) => {
const pricePercentageChanges: unknown[] = []

for (const row of rows) {
pricePercentageChanges.push(row.pop())
}
const channelsMapped = oldListQMap(rows)
return channelsMapped.map((creatorToken, i) => ({
creatorToken,
pricePercentageChange: pricePercentageChanges[i] ?? 0,
}))
}

const result = await ctx.openreader.executeQuery(listQuery)

return result as TokenReturnType[]
}

@Query(() => GetCumulativeHistoricalShareAllocationResult)
async getCumulativeHistoricalShareAllocation(
@Args() { tokenId }: GetCumulativeHistoricalShareAllocationArgs
Expand Down
30 changes: 29 additions & 1 deletion src/server-extension/resolvers/CreatorToken/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ArgsType, Field, Int, ObjectType } from 'type-graphql'
import { ArgsType, Field, Float, Int, ObjectType } from 'type-graphql'
import { GraphQLScalarType } from 'graphql'

@ArgsType()
export class GetShareDividensArgs {
Expand Down Expand Up @@ -44,3 +45,30 @@ export class GetAccountTransferrableBalanceResult {
@Field(() => Int, { nullable: false })
transferrableCrtAmount!: number
}

@ObjectType()
export class CreatorToken {
@Field(() => String, { nullable: false }) id!: string
}

@ObjectType()
export class MarketplaceTokensReturnType {
@Field(() => CreatorToken, { nullable: false }) creatorToken!: CreatorToken
@Field(() => Float, { nullable: false }) pricePercentageChange!: number
}

export const TokenWhereInput = new GraphQLScalarType({
name: 'CreatorTokenWhereInput',
})

@ArgsType()
export class MarketplaceTokensArgs {
@Field(() => TokenWhereInput, { nullable: true })
where?: Record<string, unknown>

@Field(() => Int, {
nullable: false,
description: 'The number of days in period',
})
periodDays: number
}

0 comments on commit 83c7b4d

Please sign in to comment.