From c74b8d24a6bd84f879d26be4fe472f35fd93068b Mon Sep 17 00:00:00 2001 From: ikprk Date: Mon, 15 Jul 2024 15:52:02 +0200 Subject: [PATCH] CR fixes --- db/migrations/1721051247791-Data.js | 15 ++ ...101957-Views.js => 1721051247895-Views.js} | 8 +- schema/token.graphql | 2 +- .../handlers/registerUserInteraction.ts | 5 +- src/mappings/token/index.ts | 3 +- src/model/MarketplaceToken.ts | 172 ------------------ .../resolvers/CreatorToken/index.ts | 26 +-- .../resolvers/CreatorToken/types.ts | 29 +-- .../resolvers/StateResolver/index.ts | 28 ++- src/server-extension/resolvers/baseTypes.ts | 22 +++ 10 files changed, 84 insertions(+), 226 deletions(-) create mode 100644 db/migrations/1721051247791-Data.js rename db/migrations/{1719855101957-Views.js => 1721051247895-Views.js} (83%) delete mode 100644 src/model/MarketplaceToken.ts diff --git a/db/migrations/1721051247791-Data.js b/db/migrations/1721051247791-Data.js new file mode 100644 index 000000000..a58d53a09 --- /dev/null +++ b/db/migrations/1721051247791-Data.js @@ -0,0 +1,15 @@ +module.exports = class Data1721051247791 { + name = 'Data1721051247791' + + async up(db) { + await db.query(`CREATE TABLE "admin"."marketplace_token" ("liquidity" integer, "market_cap" numeric, "cumulative_revenue" numeric, "amm_volume" numeric, "price_change" numeric, "liquidity_change" numeric, "id" character varying NOT NULL, "status" character varying(6) NOT NULL, "avatar" jsonb, "total_supply" numeric NOT NULL, "is_featured" boolean NOT NULL, "symbol" text, "is_invite_only" boolean NOT NULL, "annual_creator_reward_permill" integer NOT NULL, "revenue_share_ratio_permill" integer NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "channel_id" text, "description" text, "whitelist_applicant_note" text, "whitelist_applicant_link" text, "accounts_num" integer NOT NULL, "number_of_revenue_share_activations" integer NOT NULL, "deissued" boolean NOT NULL, "current_amm_sale_id" text, "current_sale_id" text, "current_revenue_share_id" text, "number_of_vested_transfer_issued" integer NOT NULL, "last_price" numeric, CONSTRAINT "PK_d836a8c3d907b67099c140c4d84" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_1268fd020cf195b2e8d5d85093" ON "admin"."marketplace_token" ("symbol") `) + await db.query(`CREATE INDEX "IDX_b99bb1ecee77f23016f6ef687c" ON "admin"."marketplace_token" ("created_at") `) + } + + async down(db) { + await db.query(`DROP TABLE "admin"."marketplace_token"`) + await db.query(`DROP INDEX "admin"."IDX_1268fd020cf195b2e8d5d85093"`) + await db.query(`DROP INDEX "admin"."IDX_b99bb1ecee77f23016f6ef687c"`) + } +} diff --git a/db/migrations/1719855101957-Views.js b/db/migrations/1721051247895-Views.js similarity index 83% rename from db/migrations/1719855101957-Views.js rename to db/migrations/1721051247895-Views.js index d4c237e43..de0a1ff72 100644 --- a/db/migrations/1719855101957-Views.js +++ b/db/migrations/1721051247895-Views.js @@ -1,14 +1,14 @@ const { getViewDefinitions } = require('../viewDefinitions') -module.exports = class Views1719855101957 { - name = 'Views1719855101957' +module.exports = class Views1721051247895 { + name = 'Views1721051247895' async up(db) { - // these two queries will be invoked and the cleaned up by the squid itself + // these two queries will be invoked and the cleaned up by the squid itself // we only do this to be able to reference processor height in mappings await db.query(` - CREATE SCHEMA squid_processor; + CREATE SCHEMA IF NOT EXISTS squid_processor; `) await db.query(`CREATE TABLE IF NOT EXISTS squid_processor.status ( id SERIAL PRIMARY KEY, diff --git a/schema/token.graphql b/schema/token.graphql index 7ac54b4bf..618994471 100644 --- a/schema/token.graphql +++ b/schema/token.graphql @@ -102,7 +102,7 @@ type CreatorToken @entity { lastPrice: BigInt } -type MarketplaceToken @entity { +type MarketplaceToken @entity @schema(name: "admin") { liquidity: Int marketCap: BigInt cumulativeRevenue: BigInt diff --git a/src/auth-server/handlers/registerUserInteraction.ts b/src/auth-server/handlers/registerUserInteraction.ts index a6654858e..425184c07 100644 --- a/src/auth-server/handlers/registerUserInteraction.ts +++ b/src/auth-server/handlers/registerUserInteraction.ts @@ -7,7 +7,7 @@ import { UserInteractionCount } from '../../model' import { InMemoryRateLimiter } from 'rolling-rate-limiter' -export const interactionLimiter = new InMemoryRateLimiter({ +const interactionLimiter = new InMemoryRateLimiter({ interval: 1000 * 60 * 5, // 5 minutes maxInInterval: 1, }) @@ -28,7 +28,6 @@ export const registerUserInteraction: ( const { authContext: session } = res.locals const { type, entityId } = req.body - console.log(session) if (!session) { throw new UnauthorizedError('Cannot register interactions for empty session') } @@ -58,7 +57,7 @@ export const registerUserInteraction: ( if (!dailyInteractionRow) { await em.getRepository(UserInteractionCount).save({ id: `${Date.now()}-${entityId}-${type}`, - dayTimestamp: new Date(), + dayTimestamp: new Date(date.setHours(0, 0, 0, 0)), count: 1, type, entityId, diff --git a/src/mappings/token/index.ts b/src/mappings/token/index.ts index 180038dc7..0402d286d 100644 --- a/src/mappings/token/index.ts +++ b/src/mappings/token/index.ts @@ -233,8 +233,7 @@ export async function processAmmActivatedEvent({ ammInitPrice: BigInt(intercept), finalized: false, }) - token.lastPrice = - (amm.ammSlopeParameter * BigInt(token.totalSupply)) / BigInt(2) + amm.ammInitPrice + token.lastPrice = (amm.ammSlopeParameter * token.totalSupply) / BigInt(2) + amm.ammInitPrice token.currentAmmSaleId = id const eventEntity = overlay.getRepository(Event).new({ diff --git a/src/model/MarketplaceToken.ts b/src/model/MarketplaceToken.ts deleted file mode 100644 index a797e3789..000000000 --- a/src/model/MarketplaceToken.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { Entity, Column, PrimaryColumn, Index } from 'typeorm' -import * as marshal from './generated/marshal' -import { TokenStatus } from './generated/_tokenStatus' -import { TokenAvatar, fromJsonTokenAvatar } from './generated/_tokenAvatar' - -@Entity() -export class MarketplaceToken { - constructor(props?: Partial) { - Object.assign(this, props) - } - - @Column('int4', { nullable: true }) - liquidity!: number | undefined | null - - @Column('numeric', { transformer: marshal.bigintTransformer, nullable: true }) - marketCap!: bigint | undefined | null - - @Column('numeric', { transformer: marshal.bigintTransformer, nullable: true }) - ammVolume!: bigint | undefined | null - - @Column('int4', { nullable: true }) - lastDayPriceChange!: number | undefined | null - - @Column('int4', { nullable: true }) - weeklyLiqChange!: number | undefined | null - - /** - * runtime token identifier - */ - @PrimaryColumn() - id!: string - - /** - * status sale / market / idle - */ - @Column('varchar', { length: 6, nullable: false }) - status!: TokenStatus - - /** - * avatar object (profile picture) - */ - @Column('jsonb', { - transformer: { - to: (obj) => (obj == null ? undefined : obj.toJSON()), - from: (obj) => (obj == null ? undefined : fromJsonTokenAvatar(obj)), - }, - nullable: true, - }) - avatar!: TokenAvatar | undefined | null - - /** - * total supply - */ - @Column('numeric', { transformer: marshal.bigintTransformer, nullable: false }) - totalSupply!: bigint - - /** - * Flag to indicate whether the CRT is featured or not - */ - @Column('bool', { nullable: false }) - isFeatured!: boolean - - /** - * symbol for the token uniqueness guaranteed by runtime - */ - @Index() - @Column('text', { nullable: true }) - symbol!: string | undefined | null - - /** - * access status invite only vs anyone - */ - @Column('bool', { nullable: false }) - isInviteOnly!: boolean - - /** - * creator annual revenue (minted) - */ - @Column('int4', { nullable: false }) - annualCreatorRewardPermill!: number - - /** - * revenue share ratio between creator and holder - */ - @Column('int4', { nullable: false }) - revenueShareRatioPermill!: number - - /** - * date at which this token was created - */ - @Index() - @Column('timestamp with time zone', { nullable: false }) - createdAt!: Date - - /** - * channel from which the token is issued uniqueness guaranteed by runtime - */ - @Column('text', { nullable: true }) - channelId!: string | undefined | null - - /** - * video for the token presentation page - */ - @Column('text', { nullable: true }) - trailerVideoId!: string | undefined | null - - /** - * about information displayed under the presentation video - */ - @Column('text', { nullable: true }) - description!: string | undefined | null - - /** - * note from creator to member interested in joining the whitelist - */ - @Column('text', { nullable: true }) - whitelistApplicantNote!: string | undefined | null - - /** - * link for creator to member interested in joining the whitelist - */ - @Column('text', { nullable: true }) - whitelistApplicantLink!: string | undefined | null - - /** - * number of accounts to avoid aggregate COUNT - */ - @Column('int4', { nullable: false }) - accountsNum!: number - - /** - * number of revenue shares issued - */ - @Column('int4', { nullable: false }) - numberOfRevenueShareActivations!: number - - /** - * whether it has been deissued or not - */ - @Column('bool', { nullable: false }) - deissued!: boolean - - /** - * current amm sale if ongoing - */ - @Column('text', { nullable: true }) - currentAmmSaleId!: string | undefined | null - - /** - * current sale if ongoing - */ - @Column('text', { nullable: true }) - currentSaleId!: string | undefined | null - - /** - * current revenue share if ongoing - */ - @Column('text', { nullable: true }) - currentRevenueShareId!: string | undefined | null - - /** - * number of vested transfer completed - */ - @Column('int4', { nullable: false }) - numberOfVestedTransferIssued!: number - - /** - * last unit price available - */ - @Column('numeric', { transformer: marshal.bigintTransformer, nullable: true }) - lastPrice!: bigint | undefined | null -} diff --git a/src/server-extension/resolvers/CreatorToken/index.ts b/src/server-extension/resolvers/CreatorToken/index.ts index 6f44c2e4b..00475d9c6 100644 --- a/src/server-extension/resolvers/CreatorToken/index.ts +++ b/src/server-extension/resolvers/CreatorToken/index.ts @@ -13,11 +13,9 @@ import { GetShareDividendsResult, GetShareDividensArgs, MarketplaceTokensArgs, - CreatorToken as TokenReturnType, MarketplaceTokensReturnType, TopSellingTokensReturnType, MarketplaceTableTokensArgs, - MarketplaceToken, MarketplaceTokenCount, MarketplaceTokensCountArgs, } from './types' @@ -26,6 +24,7 @@ import { parseAnyTree, parseSqlArguments } from '@subsquid/openreader/lib/opencr import { extendClause } from '../../../utils/sql' import { Context } from '../../check' import { getCurrentBlockHeight } from '../../../utils/blockHeight' +import { MarketplaceToken, CreatorToken as TokenReturnType } from '../baseTypes' export const BLOCKS_PER_DAY = 10 * 60 * 24 // 10 blocs per minute, 60 mins * 24 hours @@ -80,13 +79,18 @@ export class TokenResolver { const tokenFields = parseAnyTree(model, 'CreatorToken', info.schema, tokenSubTree) const topTokensCtes = ` -WITH tokens_volumes AS ( - SELECT ac.token_id, +WITH tokens_volumes AS ( + SELECT + ac.token_id, SUM(tr.price_paid) as ammVolume - FROM amm_transaction tr - JOIN amm_curve ac ON ac.id = tr.amm_id - WHERE tr.created_in >= ${lastProcessedBlock - args.periodDays * BLOCKS_PER_DAY} - GROUP BY token_id + FROM + amm_transaction tr + JOIN + amm_curve ac ON ac.id = tr.amm_id + WHERE + tr.created_in >= ${lastProcessedBlock - args.periodDays * BLOCKS_PER_DAY} + GROUP BY + token_id ) ` @@ -141,7 +145,7 @@ WITH tokens_volumes AS ( const result = await ctx.openreader.executeQuery(listQuery) - return result as TokenReturnType[] + return result as TopSellingTokensReturnType[] } @Query(() => [MarketplaceTokensReturnType]) @@ -325,12 +329,12 @@ END AS percentage_change offset: args.offset, }) - const videoFields = parseAnyTree(model, 'MarketplaceToken', info.schema, tree) + const marketplaceTokensFields = parseAnyTree(model, 'MarketplaceToken', info.schema, tree) const listQuery = new ListQuery( model, ctx.openreader.dialect, 'MarketplaceToken', - videoFields, + marketplaceTokensFields, sqlArgs ) diff --git a/src/server-extension/resolvers/CreatorToken/types.ts b/src/server-extension/resolvers/CreatorToken/types.ts index 361721343..990f79c10 100644 --- a/src/server-extension/resolvers/CreatorToken/types.ts +++ b/src/server-extension/resolvers/CreatorToken/types.ts @@ -1,5 +1,10 @@ import { ArgsType, Field, Float, Int, ObjectType } from 'type-graphql' -import { GraphQLScalarType } from 'graphql' +import { + CreatorToken, + MarketplaceTokenOrderByInput, + MarketplaceTokenWhereInput, + TokenWhereInput, +} from '../baseTypes' @ArgsType() export class GetShareDividensArgs { @@ -46,11 +51,6 @@ export class GetAccountTransferrableBalanceResult { transferrableCrtAmount!: number } -@ObjectType() -export class CreatorToken { - @Field(() => String, { nullable: false }) id!: string -} - @ObjectType() export class MarketplaceTokensReturnType { @Field(() => CreatorToken, { nullable: false }) creatorToken!: CreatorToken @@ -63,10 +63,6 @@ export class TopSellingTokensReturnType { @Field(() => String, { nullable: false }) ammVolume!: string } -export const TokenWhereInput = new GraphQLScalarType({ - name: 'CreatorTokenWhereInput', -}) - @ArgsType() export class MarketplaceTokensArgs { @Field(() => TokenWhereInput, { nullable: true }) @@ -90,19 +86,6 @@ export class MarketplaceTokensArgs { orderByPriceDesc: boolean | null } -export const MarketplaceTokenWhereInput = new GraphQLScalarType({ - name: 'MarketplaceTokenWhereInput', -}) - -export const MarketplaceTokenOrderByInput = new GraphQLScalarType({ - name: 'id_ASC', -}) - -@ObjectType() -export class MarketplaceToken { - @Field(() => String, { nullable: false }) id!: string -} - @ObjectType() export class MarketplaceTokenCount { @Field(() => Int, { nullable: false }) count: number diff --git a/src/server-extension/resolvers/StateResolver/index.ts b/src/server-extension/resolvers/StateResolver/index.ts index 3178caa60..3a1e12b73 100644 --- a/src/server-extension/resolvers/StateResolver/index.ts +++ b/src/server-extension/resolvers/StateResolver/index.ts @@ -80,20 +80,28 @@ export class StateResolver { } @Query(() => [TopInteractedEntity]) - async getTopInteractedEnities( + async getTopInteractedEntities( @Args() args: TopInteractedEntityArgs ): Promise { const em = await this.tx() - const result: { entity_id: string; entrycount: number }[] = await em.query(` -SELECT entity_id, SUM(count) as entryCount - FROM admin.user_interaction_count - WHERE type = '${args.type}' - AND day_timestamp >= NOW() - INTERVAL '${args.period} DAYS' - GROUP BY entity_id - ORDER BY entryCount DESC - LIMIT 10; -`) + const result: { entity_id: string; entrycount: number }[] = await em.query( + ` +SELECT + entity_id, + SUM(count) as entryCount +FROM + admin.user_interaction_count +WHERE + type = $1 AND day_timestamp >= NOW() - INTERVAL '$2 DAYS' +GROUP BY + entity_id +ORDER BY + entryCount DESC +LIMIT 10; +`, + [args.type, args.period] + ) return result.map((res) => ({ interactionCount: res.entrycount, diff --git a/src/server-extension/resolvers/baseTypes.ts b/src/server-extension/resolvers/baseTypes.ts index c42145544..41d24acae 100644 --- a/src/server-extension/resolvers/baseTypes.ts +++ b/src/server-extension/resolvers/baseTypes.ts @@ -61,3 +61,25 @@ export class VideosConnection { export const OwnedNftWhereInput = new GraphQLScalarType({ name: 'OwnedNftWhereInput', }) + +@ObjectType() +export class CreatorToken { + @Field(() => String, { nullable: false }) id!: string +} + +export const TokenWhereInput = new GraphQLScalarType({ + name: 'CreatorTokenWhereInput', +}) + +export const MarketplaceTokenWhereInput = new GraphQLScalarType({ + name: 'MarketplaceTokenWhereInput', +}) + +export const MarketplaceTokenOrderByInput = new GraphQLScalarType({ + name: 'id_ASC', +}) + +@ObjectType() +export class MarketplaceToken { + @Field(() => String, { nullable: false }) id!: string +}