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

Add missing fields #110

Merged
merged 32 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0defebc
proper count on token entity
daiagi Oct 4, 2023
2456fc3
remove exapnsive debug logs
daiagi Oct 4, 2023
3ec22b8
slim down - pass only collection id
daiagi Oct 4, 2023
0bcaafc
better debug logging
daiagi Oct 4, 2023
e470451
cheapest nft
daiagi Oct 4, 2023
3ae7031
improve performance
daiagi Oct 6, 2023
88a43f1
Merge branch 'tokenEnityt/fix-count-calc' of https://github.com/daiag…
daiagi Oct 6, 2023
0a93e90
resolver for tokenEntities of specific owner
daiagi Oct 6, 2023
0db457c
add metadata and meta to TokenEntity
daiagi Oct 6, 2023
2917612
add totalCount field to avoid bug when delting token
daiagi Oct 6, 2023
ef65343
Merge branch 'tokenEnityt/fix-count-calc' of https://github.com/daiag…
daiagi Oct 6, 2023
7e6e5dc
merge migration files
daiagi Oct 6, 2023
cd0de70
add meta and metadata to resolver
daiagi Oct 6, 2023
810718e
schema and migration
daiagi Oct 8, 2023
6559ba3
re orgenize
daiagi Oct 8, 2023
9a4aa70
schema name changes
daiagi Oct 8, 2023
4578868
name changes- resolver
daiagi Oct 8, 2023
96036d3
oops - undo comment out of unique handlers
daiagi Oct 8, 2023
3a97b0d
undo migration change
daiagi Oct 8, 2023
cbeda90
supply on resolver
daiagi Oct 8, 2023
8402c5e
use more utils
daiagi Oct 9, 2023
9eae7d8
fix orderBy, add denyList, owner can be null,
daiagi Oct 10, 2023
eb9a4dd
add collection floor price, fix typings
daiagi Oct 10, 2023
b5963dc
cheapest is already on tokenEntity
daiagi Oct 10, 2023
c684a66
total count resolver
daiagi Oct 10, 2023
7060884
drop collection floor price
daiagi Oct 10, 2023
789ff7b
syntax fix
daiagi Oct 10, 2023
6671e29
get 'cheapest' in resolver, drop it from schema
daiagi Oct 11, 2023
d858519
add current owner
daiagi Oct 11, 2023
40a43d4
`SELECT DISTINCT` to improve query performance
daiagi Oct 11, 2023
23ac70a
cheapest can have price:0
daiagi Oct 12, 2023
76692c8
😱 uncomment unique tranfer
daiagi Oct 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions db/migrations/1696751796584-Data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = class Data1696751796584 {
name = 'Data1696751796584'

async up(db) {
await db.query(`ALTER TABLE "token_entity" ADD "metadata" text`)
await db.query(`ALTER TABLE "token_entity" ADD "supply" integer NOT NULL`)
await db.query(`ALTER TABLE "token_entity" ADD "cheapest_id" character varying`)
await db.query(`ALTER TABLE "token_entity" ADD "meta_id" character varying`)
await db.query(`CREATE INDEX "IDX_637db5c040f1d9f935817ae1e8" ON "token_entity" ("cheapest_id") `)
await db.query(`CREATE INDEX "IDX_ae4ff3b28e3fec72aa14124d1e" ON "token_entity" ("meta_id") `)
await db.query(`ALTER TABLE "token_entity" ADD CONSTRAINT "FK_637db5c040f1d9f935817ae1e8a" FOREIGN KEY ("cheapest_id") REFERENCES "nft_entity"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`)
await db.query(`ALTER TABLE "token_entity" ADD CONSTRAINT "FK_ae4ff3b28e3fec72aa14124d1e1" FOREIGN KEY ("meta_id") REFERENCES "metadata_entity"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`)
}

async down(db) {
await db.query(`ALTER TABLE "token_entity" DROP COLUMN "metadata"`)
await db.query(`ALTER TABLE "token_entity" DROP COLUMN "supply"`)
await db.query(`ALTER TABLE "token_entity" DROP COLUMN "cheapest_id"`)
await db.query(`ALTER TABLE "token_entity" DROP COLUMN "meta_id"`)
await db.query(`DROP INDEX "public"."IDX_637db5c040f1d9f935817ae1e8"`)
await db.query(`DROP INDEX "public"."IDX_ae4ff3b28e3fec72aa14124d1e"`)
await db.query(`ALTER TABLE "token_entity" DROP CONSTRAINT "FK_637db5c040f1d9f935817ae1e8a"`)
await db.query(`ALTER TABLE "token_entity" DROP CONSTRAINT "FK_ae4ff3b28e3fec72aa14124d1e1"`)
}
}
3 changes: 3 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ type TokenEntity @entity {
hash: String! @index
image: String
media: String
meta: MetadataEntity
metadata: String
name: String @index
updatedAt: DateTime!
createdAt: DateTime!
supply: Int!
count: Int!
}

Expand Down
5 changes: 4 additions & 1 deletion src/mappings/nfts/burn.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { getWith } from '@kodadot1/metasquid/entity'
import { getWith } from '@kodadot1/metasquid/entity'
import { NFTEntity as NE } from '../../model'
import { unwrap } from '../utils/extract'
import { debug, pending, success } from '../utils/logger'
import { Action, Context, createTokenId } from '../utils/types'
import { createEvent } from '../shared/event'
import { calculateCollectionOwnerCountAndDistribution } from '../utils/helper'
import { burnHandler } from '../shared/token'
import { getBurnTokenEvent } from './getters'

const OPERATION = Action.BURN
Expand All @@ -31,6 +32,8 @@ export async function handleTokenBurn(context: Context): Promise<void> {
entity.collection.ownerCount = ownerCount
entity.collection.distribution = distribution

await burnHandler(context, entity)

success(OPERATION, `${id} by ${event.caller}}`)
await context.store.save(entity)
const meta = entity.metadata ?? ''
Expand Down
1 change: 0 additions & 1 deletion src/mappings/nfts/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export async function handleTokenList(context: Context): Promise<void> {
if (entity.price && (entity.collection.floor === 0n || entity.price < entity.collection.floor)) {
entity.collection.floor = entity.price
}

success(OPERATION, `${id} by ${event.caller}} for ${String(event.price)}`)
await context.store.save(entity)
const meta = String(event.price || '')
Expand Down
3 changes: 3 additions & 0 deletions src/mappings/nfts/mint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { unwrap } from '../utils/extract'
import { debug, pending, success } from '../utils/logger'
import { Action, Context, createTokenId } from '../utils/types'
import { calculateCollectionOwnerCountAndDistribution, versionOf } from '../utils/helper'
import { mintHandler } from '../shared/token'
import { getCreateTokenEvent } from './getters'

const OPERATION = Action.MINT
Expand Down Expand Up @@ -60,6 +61,8 @@ export async function handleTokenCreate(context: Context): Promise<void> {
final.name = metadata?.name
final.image = metadata?.image
final.media = metadata?.animationUrl

await mintHandler(context, collection, final)
}

success(OPERATION, `${final.id}`)
Expand Down
16 changes: 7 additions & 9 deletions src/mappings/nfts/setMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CollectionEntity, NFTEntity } from '../../model'
import { handleMetadata } from '../shared/metadata'
import { debug, warn } from '../utils/logger'
import { updateItemMetadataByCollection } from '../utils/cache'
import { handleTokenEntity } from '../shared/handleTokenEntity'
import { setMetadataHandler } from '../shared/token'
import { tokenIdOf } from './types'
import { getMetadataEvent } from './getters'

Expand Down Expand Up @@ -51,17 +51,15 @@ export async function handleMetadataSet(context: Context): Promise<void> {
warn(OPERATION, `collection ${event.collectionId} not found`)
return
}
const nft = final as NFTEntity
const token = await handleTokenEntity(context, collection, nft)
if (token) {
nft.token = token
if (final instanceof NFTEntity) {
await setMetadataHandler(context, collection, final)
}
}
}

await context.store.save(final)
await context.store.save(final)

if (!event.sn && final.metadata) {
await updateItemMetadataByCollection(context.store, event.collectionId)
if (!event.sn && final.metadata) {
await updateItemMetadataByCollection(context.store, event.collectionId)
}
}
}
44 changes: 0 additions & 44 deletions src/mappings/shared/handleTokenEntity.ts

This file was deleted.

24 changes: 24 additions & 0 deletions src/mappings/shared/token/burn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { getOptional } from '@kodadot1/metasquid/entity'
import { Context } from '../../utils/types'
import { NFTEntity as NE, TokenEntity as TE } from '../../../model'
import { debug } from '../../utils/logger'
import { OPERATION, generateTokenId, mediaOf } from './utils'

export async function burnHandler(context: Context, nft: NE): Promise<void> {
debug(OPERATION, { handleBurn: `Handle Burn for NFT ${nft.id}` })

const nftMedia = mediaOf(nft)
if (!nftMedia) {
return
}

const token = await getOptional<TE>(context.store, TE, generateTokenId(nft.collection.id, nftMedia))

if (!token) {
return
}

debug(OPERATION, { BURN: `decrement Token's ${token.id} supply` })

await context.store.update(TE, token.id, { supply: token.supply - 1, updatedAt: nft.updatedAt })
}
3 changes: 3 additions & 0 deletions src/mappings/shared/token/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './mint'
export * from './setMetadata'
export * from './burn'
20 changes: 20 additions & 0 deletions src/mappings/shared/token/mint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { getOptional } from '@kodadot1/metasquid/entity'
import { Context } from '../../utils/types'
import { CollectionEntity as CE, NFTEntity as NE, TokenEntity as TE } from '../../../model'
import { debug } from '../../utils/logger'
import { OPERATION, generateTokenId, mediaOf } from './utils'
import { TokenAPI } from './tokenAPI'

export async function mintHandler(context: Context, collection: CE, nft: NE): Promise<TE | undefined> {
vikiival marked this conversation as resolved.
Show resolved Hide resolved
debug(OPERATION, { mintHandler: `Handle mint for NFT ${nft.id}` })

const nftMedia = mediaOf(nft)
if (!nftMedia) {
return
}

const tokenApi = new TokenAPI(context.store)

const existingToken = await getOptional<TE>(context.store, TE, generateTokenId(collection.id, nftMedia))
return await (existingToken ? tokenApi.addNftToToken(nft, existingToken) : tokenApi.create(collection, nft))
}
32 changes: 32 additions & 0 deletions src/mappings/shared/token/setMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { getOptional, getWith } from '@kodadot1/metasquid/entity'
import { Context } from '../../utils/types'
import { CollectionEntity as CE, NFTEntity as NE, TokenEntity as TE } from '../../../model'
import { debug, warn } from '../../utils/logger'
import { OPERATION, generateTokenId, mediaOf } from './utils'
import { TokenAPI } from './tokenAPI'

export async function setMetadataHandler(context: Context, collection: CE, nft: NE): Promise<TE | undefined> {
vikiival marked this conversation as resolved.
Show resolved Hide resolved
debug(OPERATION, { handleMetadataSet: `Handle set metadata for NFT ${nft.id}` })
const nftMedia = mediaOf(nft)
if (!nftMedia) {
return
}

let nftWithToken, existingToken
try {
[nftWithToken, existingToken] = await Promise.all([
getWith(context.store, NE, nft.id, { token: true }),
getOptional<TE>(context.store, TE, generateTokenId(collection.id, nftMedia)),
])
} catch (error) {
warn(OPERATION, `ERROR ${error}`)
return
}

const tokenAPI = new TokenAPI(context.store)

if (nftWithToken.token) {
await tokenAPI.removeNftFromToken(nft, nftWithToken.token)
}
return await (existingToken ? tokenAPI.addNftToToken(nft, existingToken) : tokenAPI.create(collection, nft))
}
73 changes: 73 additions & 0 deletions src/mappings/shared/token/tokenAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { create as createEntity } from '@kodadot1/metasquid/entity'
import md5 from 'md5'
import { Store } from '../../utils/types'
import { CollectionEntity as CE, NFTEntity as NE, TokenEntity as TE } from '../../../model'
import { debug } from '../../utils/logger'
import { OPERATION, generateTokenId, mediaOf, tokenName } from './utils'

export class TokenAPI {
constructor(private store: Store) {}

async create(collection: CE, nft: NE): Promise<TE | undefined> {
const nftMedia = mediaOf(nft)
if (!nftMedia) {
return
}
const tokenId = generateTokenId(collection.id, nftMedia)
debug(OPERATION, { createToken: `Create TOKEN ${tokenId} for NFT ${nft.id}` })

const token = createEntity(TE, tokenId, {
createdAt: nft.createdAt,
collection,
name: tokenName(nft.name),
count: 1,
supply: 1,
hash: md5(tokenId),
image: nft.image,
media: nft.media,
metadata: nft.metadata,
meta: nft.meta,
blockNumber: nft.blockNumber,
updatedAt: nft.updatedAt,
id: tokenId,
})

await this.store.save(token)
await this.store.update(NE, nft.id, { token })

return token
}

async removeNftFromToken(nft: NE, token: TE): Promise<void> {
if (!token) {
return
}
debug(OPERATION, { removeNftFromToken: `Unlink NFT ${nft.id} from TOKEN ${token.id}` })

await this.store.update(NE, nft.id, { token: null })
const updatedCount = token.count - 1
await this.store.update(TE, token.id, {
supply: token.supply - 1,
count: updatedCount,
updatedAt: nft.updatedAt,
})

if (updatedCount === 0) {
debug(OPERATION, { deleteEmptyToken: `delete empty token ${token.id}` })

await this.store.delete(TE, token.id)
}
}

async addNftToToken(nft: NE, token: TE): Promise<TE> {
debug(OPERATION, { updateToken: `Add NFT ${nft.id} to TOKEN ${token.id} for ` })
token.count += 1
token.supply += 1
token.updatedAt = nft.updatedAt
nft.token = token
await this.store.save(token)
await this.store.save(nft)

return token
}
}
23 changes: 23 additions & 0 deletions src/mappings/shared/token/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import md5 from 'md5'
import { NFTEntity as NE } from '../../../model'
import { warn } from '../../utils/logger'

export const OPERATION = 'TokenEntity' as any

export function generateTokenId(collectionId: string, nftMedia: string): string {
return `${collectionId}-${md5(nftMedia)}`
}

export const mediaOf = (nft: NE): string | undefined => {
vikiival marked this conversation as resolved.
Show resolved Hide resolved
const nftMedia = nft.image ?? nft.media

if (!nftMedia || nftMedia === '') {
warn(OPERATION, `MISSING NFT MEDIA ${nft.id}`)
return undefined
}

return nftMedia
}

export const tokenName = (nftName: string | undefined | null): string =>
typeof nftName === 'string' ? nftName?.replace(/([#_]\d+$)/g, '').trim() : ''
3 changes: 3 additions & 0 deletions src/mappings/uniques/burn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { debug, pending, success } from '../utils/logger'
import { Action, Context, createTokenId } from '../utils/types'
import { createEvent } from '../shared/event'
import { calculateCollectionOwnerCountAndDistribution } from '../utils/helper'
import { burnHandler } from '../shared/token'
import { getBurnTokenEvent } from './getters'

const OPERATION = Action.BURN
Expand All @@ -31,6 +32,8 @@ export async function handleTokenBurn(context: Context): Promise<void> {
entity.collection.ownerCount = ownerCount
entity.collection.distribution = distribution

await burnHandler(context, entity)

success(OPERATION, `${id} by ${event.caller}}`)
await context.store.save(entity)
const meta = entity.metadata ?? ''
Expand Down
1 change: 1 addition & 0 deletions src/mappings/uniques/buy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export async function handleTokenBuy(context: Context): Promise<void> {
entity.collection.ownerCount = ownerCount
entity.collection.distribution = distribution


success(OPERATION, `${id} by ${event.caller} for ${String(event.price)}`)
await context.store.save(entity)
const meta = String(event.price || '')
Expand Down
9 changes: 3 additions & 6 deletions src/mappings/uniques/mint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { handleMetadata } from '../shared/metadata'
import { unwrap } from '../utils/extract'
import { debug, pending, success } from '../utils/logger'
import { Action, Context, createTokenId } from '../utils/types'
import { versionOf , calculateCollectionOwnerCountAndDistribution } from '../utils/helper'
import { handleTokenEntity } from '../shared/handleTokenEntity'
import { versionOf, calculateCollectionOwnerCountAndDistribution } from '../utils/helper'
import { mintHandler } from '../shared/token'
import { getCreateTokenEvent } from './getters'

const OPERATION = Action.MINT
Expand Down Expand Up @@ -63,10 +63,7 @@ export async function handleTokenCreate(context: Context): Promise<void> {
final.media = metadata?.animationUrl
}

const token = await handleTokenEntity(context, collection, final)
if (token) {
final.token = token
}
await mintHandler(context, collection, final)

success(OPERATION, `${final.id}`)
await context.store.save(final)
Expand Down
Loading