Skip to content

Commit

Permalink
Merge pull request #31 from daiagi/TokenEntity
Browse files Browse the repository at this point in the history
  • Loading branch information
vikiival authored Jul 8, 2023
2 parents 90e35a2 + e3c682d commit 1a6c8a6
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 21 deletions.
16 changes: 16 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ type CollectionEntity @entity {
volume: BigInt!
}

type TokenEntity @entity {
id: ID!
blockNumber: BigInt
collection: CollectionEntity
nfts: [NFTEntity!] @derivedFrom(field: "token")
hash: String! @index
image: String
media: String
name: String @index
updatedAt: DateTime!
createdAt: DateTime!
count: Int!
}

type NFTEntity @entity {
attributes: [Attribute!]
blockNumber: BigInt
Expand All @@ -49,6 +63,8 @@ type NFTEntity @entity {
sn: String!
updatedAt: DateTime!
version: Int!
token: TokenEntity!

}

type MetadataEntity @entity {
Expand Down
35 changes: 26 additions & 9 deletions src/mappings/nfts/setMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
import { get } from '@kodadot1/metasquid/entity'
import { get, getOptional } from '@kodadot1/metasquid/entity'
import { isFetchable } from '@kodadot1/minipfs'
import { unwrap } from '../utils/extract'
import { Context } from '../utils/types'
import { Context, isNFT } from '../utils/types'
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 { tokenIdOf } from './types'
import { getMetadataEvent } from './getters'

const OPERATION = 'METADATA' as any
export async function handleMetadataSet(context: Context): Promise<void> {
const event = unwrap(context, getMetadataEvent)
debug('METADATA' as any, event)
debug(OPERATION, event)

if (!event.metadata) {
return
}

const final =
event.sn !== undefined
? await get(context.store, NFTEntity, tokenIdOf(event as any))
: await get(context.store, CollectionEntity, event.collectionId)
const eventIsOnNFT = isNFT(event)

const final = eventIsOnNFT
? await get(context.store, NFTEntity, tokenIdOf(event as any))
: await get(context.store, CollectionEntity, event.collectionId)

if (!final) {
warn('METADATA' as any, `MISSING ${event.collectionId}-${event.sn}`)
warn(OPERATION, `MISSING ${event.collectionId}-${event.sn}`)
return
}

if (!isFetchable(event.metadata)) {
warn('METADATA' as any, `NOT FETCHABLE ${event.collectionId}-${event.sn} ${event.metadata}`)
warn(OPERATION, `NOT FETCHABLE ${event.collectionId}-${event.sn} ${event.metadata}`)
return
}

Expand All @@ -40,6 +43,20 @@ export async function handleMetadataSet(context: Context): Promise<void> {
final.name = metadata?.name
final.image = metadata?.image
final.media = metadata?.animationUrl

if (eventIsOnNFT) {
const collection = await getOptional<CollectionEntity>(context.store, CollectionEntity, event.collectionId)

if (!collection) {
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
}
}
}

await context.store.save(final)
Expand Down
44 changes: 44 additions & 0 deletions src/mappings/shared/handleTokenEntity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { create, getOptional } from '@kodadot1/metasquid/entity'
import md5 from 'md5'
import { CollectionEntity as CE, NFTEntity as NE, TokenEntity as TE } from '../../model'
import { warn } from '../utils/logger'
import { Context } from '../utils/types'

const OPERATION = 'TokenEntity' as any

export async function handleTokenEntity(context: Context, collection: CE, nft: NE): Promise<TE | undefined> {
const nftMedia = nft.image || nft.media
if (!nftMedia || nftMedia === '') {
warn(OPERATION, `MISSING NFT MEDIA ${nft.id}`)
return
}

const tokenId = `${collection.id}-${md5(nftMedia)}`
let token = await getOptional<TE>(context.store, TE, tokenId)

if (!token) {
const tokenName = (typeof nft.name === 'string' ? nft.name?.replace(/([#_]\d+$)/g, '').trim() : '')

token = create(TE, tokenId, {
createdAt: nft.createdAt,
collection,
name: tokenName,
count: 1,
hash: md5(tokenId),
image: nft.image,
media: nft.media,
blockNumber: nft.blockNumber,
updatedAt: nft.updatedAt,
id: tokenId,
})
} else {
token.count += 1
}

token.updatedAt = nft.updatedAt
token.blockNumber = nft.blockNumber

await context.store.save(token)

return token
}
36 changes: 27 additions & 9 deletions src/mappings/uniques/setMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
import { get } from '@kodadot1/metasquid/entity'
import { get, getOptional } from '@kodadot1/metasquid/entity'
import { isFetchable } from '@kodadot1/minipfs'
import { unwrap } from '../utils/extract'
import { Context } from '../utils/types'
import { Context, isNFT } from '../utils/types'
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 { tokenIdOf } from './types'
import { getMetadataEvent } from './getters'

const OPERATION = 'METADATA' as any

export async function handleMetadataSet(context: Context): Promise<void> {
const event = unwrap(context, getMetadataEvent)
debug('METADATA' as any, event)
debug(OPERATION, event)

if (!event.metadata) {
return
}

const final =
event.sn !== undefined
? await get(context.store, NFTEntity, tokenIdOf(event as any))
: await get(context.store, CollectionEntity, event.collectionId)
const eventIsOnNFT = isNFT(event)

const final = eventIsOnNFT
? await get(context.store, NFTEntity, tokenIdOf(event as any))
: await get(context.store, CollectionEntity, event.collectionId)

if (!final) {
warn('METADATA' as any, `MISSING ${event.collectionId}-${event.sn}`)
warn(OPERATION, `MISSING ${event.collectionId}-${event.sn}`)
return
}

if (!isFetchable(event.metadata)) {
warn('METADATA' as any, `NOT FETCHABLE ${event.collectionId}-${event.sn} ${event.metadata}`)
warn(OPERATION, `NOT FETCHABLE ${event.collectionId}-${event.sn} ${event.metadata}`)
return
}

Expand All @@ -40,6 +44,20 @@ export async function handleMetadataSet(context: Context): Promise<void> {
final.name = metadata?.name
final.image = metadata?.image
final.media = metadata?.animationUrl

if (eventIsOnNFT) {
const collection = await getOptional<CollectionEntity>(context.store, CollectionEntity, event.collectionId)

if (!collection) {
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
}
}
}

await context.store.save(final)
Expand Down
9 changes: 6 additions & 3 deletions src/mappings/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import { EntityManager } from 'typeorm'
// import { Attribute } from '../../model/generated/_attribute';

import { Interaction } from '../../model'
import { SetMetadata } from '../nfts/types'

export type BaseCall = {
caller: string
blockNumber: string
timestamp: Date
}



export type CollectionInteraction = Interaction.CREATE | Interaction.DESTROY

type OneOfInteraction = Interaction
Expand All @@ -26,6 +25,10 @@ export function collectionEventFrom(
return eventFrom<CollectionInteraction>(interaction, basecall, meta)
}

export function isNFT<T extends SetMetadata>(event: T) {
return event.sn !== undefined
}

export function eventFrom<T>(
interaction: T,
{ blockNumber, caller, timestamp }: BaseCall,
Expand Down Expand Up @@ -119,4 +122,4 @@ export enum DisplayType {
'boost_percentage',
}

export { Interaction as Action } from '../../model'
export { Interaction as Action } from '../../model'
1 change: 1 addition & 0 deletions src/model/generated/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./collectionEntity.model"
export * from "./_attribute"
export * from "./tokenEntity.model"
export * from "./nftEntity.model"
export * from "./metadataEntity.model"
export * from "./event.model"
Expand Down
5 changes: 5 additions & 0 deletions src/model/generated/nftEntity.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {Attribute} from "./_attribute"
import {CollectionEntity} from "./collectionEntity.model"
import {Event} from "./event.model"
import {MetadataEntity} from "./metadataEntity.model"
import {TokenEntity} from "./tokenEntity.model"

@Entity_()
export class NFTEntity {
Expand Down Expand Up @@ -81,4 +82,8 @@ export class NFTEntity {

@Column_("int4", {nullable: false})
version!: number

@Index_()
@ManyToOne_(() => TokenEntity, {nullable: true})
token!: TokenEntity
}
47 changes: 47 additions & 0 deletions src/model/generated/tokenEntity.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, ManyToOne as ManyToOne_, Index as Index_, OneToMany as OneToMany_} from "typeorm"
import * as marshal from "./marshal"
import {CollectionEntity} from "./collectionEntity.model"
import {NFTEntity} from "./nftEntity.model"

@Entity_()
export class TokenEntity {
constructor(props?: Partial<TokenEntity>) {
Object.assign(this, props)
}

@PrimaryColumn_()
id!: string

@Column_("numeric", {transformer: marshal.bigintTransformer, nullable: true})
blockNumber!: bigint | undefined | null

@Index_()
@ManyToOne_(() => CollectionEntity, {nullable: true})
collection!: CollectionEntity | undefined | null

@OneToMany_(() => NFTEntity, e => e.token)
nfts!: NFTEntity[]

@Index_()
@Column_("text", {nullable: false})
hash!: string

@Column_("text", {nullable: true})
image!: string | undefined | null

@Column_("text", {nullable: true})
media!: string | undefined | null

@Index_()
@Column_("text", {nullable: true})
name!: string | undefined | null

@Column_("timestamp with time zone", {nullable: false})
updatedAt!: Date

@Column_("timestamp with time zone", {nullable: false})
createdAt!: Date

@Column_("int4", {nullable: false})
count!: number
}

0 comments on commit 1a6c8a6

Please sign in to comment.