Skip to content

Commit 9886149

Browse files
authored
Merge pull request #314 from kodadot/main
🔖 Stick v12
2 parents fa610b2 + fa9b511 commit 9886149

31 files changed

+336
-320
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,14 @@ CHAIN=polkadot # or kusama
162162
OFFER=<ID_OF_THE_COLLECTION>
163163
```
164164

165+
6. debugging the processor
166+
167+
As the processor can run for a longer period of time it is useful to turn off the "features" that you do not need,
168+
Handlers that need to be always enabled are `createCollection` and `createItem` as they are the base for the rest of the processor.
169+
170+
> [!NOTE]
171+
> If you do not wish to index `uniques` pallet you can turn it off by setting `UNIQUES_ENABLED=false` in `.env` file
172+
165173
### Note on Swaps
166174

167175
1. Swaps can be overwritten at any time

db/migrations/1726485003107-Data.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module.exports = class Data1726485003107 {
2+
name = 'Data1726485003107'
3+
4+
async up(db) {
5+
await db.query(`ALTER TABLE "metadata_entity" ADD "kind" character varying(6)`)
6+
await db.query(`ALTER TABLE "collection_entity" ADD "kind" character varying(6)`)
7+
}
8+
9+
async down(db) {
10+
await db.query(`ALTER TABLE "metadata_entity" DROP COLUMN "kind"`)
11+
await db.query(`ALTER TABLE "collection_entity" DROP COLUMN "kind"`)
12+
}
13+
}

package-lock.json

+125-121
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
"query-node:start": "squid-graphql-server --subscriptions --max-response-size 10000 --dumb-cache in-memory --dumb-cache-ttl 1000 --dumb-cache-size 100 --dumb-cache-max-age 1000"
1717
},
1818
"dependencies": {
19-
"@kodadot1/hyperdata": "^0.0.1-rc.4",
19+
"@kodadot1/hyperdata": "^0.0.1-rc.5",
2020
"@kodadot1/metasquid": "^0.3.1-rc.0",
2121
"@kodadot1/minipfs": "^0.4.3-rc.2",
2222
"@subsquid/archive-registry": "3.3.2",
23-
"@subsquid/graphql-server": "4.6.0",
23+
"@subsquid/graphql-server": "4.7.0",
2424
"@subsquid/ss58": "2.0.2",
25-
"@subsquid/substrate-processor": "8.4.1",
25+
"@subsquid/substrate-processor": "8.5.1",
2626
"@subsquid/typeorm-migration": "1.3.0",
2727
"@subsquid/typeorm-store": "1.5.1",
2828
"dotenv": "^16.4.5",
@@ -33,9 +33,9 @@
3333
"typeorm": "0.3.17"
3434
},
3535
"devDependencies": {
36-
"@subsquid/substrate-metadata-explorer": "3.1.2",
36+
"@subsquid/substrate-metadata-explorer": "3.2.0",
3737
"@subsquid/substrate-typegen": "8.1.0",
38-
"@subsquid/typeorm-codegen": "2.0.1",
38+
"@subsquid/typeorm-codegen": "2.0.2",
3939
"@types/md5": "^2.3.5",
4040
"@types/node": "18.11.18",
4141
"@types/pg": "^8.11.4",

schema.graphql

+11
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type CollectionEntity @entity {
1616
id: ID!
1717
image: String
1818
issuer: String!
19+
kind: Kind
1920
max: Int
2021
media: String
2122
meta: MetadataEntity
@@ -97,6 +98,7 @@ type MetadataEntity @entity {
9798
animationUrl: String
9899
type: String
99100
banner: String
101+
kind: Kind
100102
}
101103

102104
# Entity to represent an Attribute
@@ -259,6 +261,15 @@ enum TradeStatus {
259261
WITHDRAWN
260262
}
261263

264+
enum Kind {
265+
poap
266+
pfp
267+
genart
268+
mixed
269+
# audio
270+
# video
271+
}
272+
262273
# Entity to represent a Fungible Asset
263274
# defined on chain as pub type Asset<T: Config<I>, I: 'static = ()>
264275
# https://github.com/paritytech/polkadot-sdk/blob/99234440f0f8b24f7e4d1d3a0102a9b19a408dd3/substrate/frame/assets/src/lib.rs#L325

speck.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
manifestVersion: subsquid.io/v0.1
22
name: speck
3-
version: 13
3+
version: 14
44
description: 'SubSquid indexer for Uniques and Assets on Statemint'
55
build:
66
deploy:
@@ -16,6 +16,7 @@ deploy:
1616
env:
1717
CHAIN: polkadot
1818
OFFER: 174
19+
UNIQUES_ENABLED: true
1920
api:
2021
cmd:
2122
- npx

squid.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ deploy:
1616
env:
1717
CHAIN: kusama
1818
OFFER: 464
19+
UNIQUES_ENABLED: true
1920
api:
2021
cmd:
2122
- npx

src/environment.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ export type Chain = 'kusama' | 'rococo' | 'polkadot'
33
export const CHAIN: Chain = process.env.CHAIN as Chain || 'kusama'
44
export const COLLECTION_OFFER: string = process.env.OFFER || ''
55

6+
export const UNIQUES_ENABLED = process.env.UNIQUES === 'true'
67
const UNIQUE_STARTING_BLOCK = 323_750 // 618838;
7-
// const _NFT_STARTING_BLOCK = 4_556_552
8-
export const STARTING_BLOCK = UNIQUE_STARTING_BLOCK
8+
const NFT_STARTING_BLOCK = 4_556_552
9+
export const STARTING_BLOCK = UNIQUES_ENABLED ? UNIQUE_STARTING_BLOCK : NFT_STARTING_BLOCK
910

1011
// Asset Hub
1112
const ARCHIVE_URL = `https://v2.archive.subsquid.io/network/asset-hub-${CHAIN}`
@@ -16,6 +17,7 @@ export const isProd = CHAIN !== 'rococo'
1617
console.table({
1718
CHAIN, ARCHIVE_URL, NODE_URL, STARTING_BLOCK,
1819
COLLECTION_OFFER,
20+
UNIQUES_ENABLED,
1921
disabledRPC: false,
2022
environment: isProd ? 'production' : 'development',
2123
})

src/mappings/index.ts

+18-98
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import * as a from './assets'
88
import * as n from './nfts'
99
import * as u from './uniques'
1010
import { BatchContext, Context, SelectedEvent } from './utils/types'
11-
import { updateCache } from './utils/cache'
12-
import { logError } from './utils/logger'
11+
import { updateOfferCache } from './utils/cache'
1312

1413
type HandlerFunction = <T extends SelectedEvent>(item: T, ctx: Context) => Promise<void>
1514

@@ -234,105 +233,26 @@ export async function mainFrame(ctx: BatchContext<Store>): Promise<void> {
234233
}
235234
}
236235

237-
// const lastDate = new Date(ctx.blocks[ctx.blocks.length - 1].header.timestamp || start)
238-
// await updateCache(lastDate, ctx.store)
239-
240-
// const { contracts, tokens } = uniqueEntitySets(items)
241-
// const collections = await finalizeCollections(contracts, ctx)
242-
// const finish = await whatToDoWithTokens({ tokens, collections, items }, ctx)
243-
// const complete = await completeTokens(ctx, finish)
244-
245-
// logger.info(`Batch completed, ${complete.length} tokens saved`)
236+
if (ctx.isHead) {
237+
const lastBlock = ctx.blocks[ctx.blocks.length - 1].header
238+
const lastDate = new Date(lastBlock.timestamp || Date.now())
239+
logger.info(`Found head block, updating cache`)
240+
await updateOfferCache(lastDate, lastBlock.height, ctx.store)
241+
}
246242
}
247243

248-
// function unwrapLog(log: Log, block: BlockData) {
249-
// switch (log.topics[0]) {
250-
// case ERC721_TRANSFER:
244+
// class Head {
245+
// #height: number
251246

252-
// if (log.address !== Contracts.HueNft) {
253-
// return null
254-
// }
255-
// return handle721Token(log, block)
256-
// default:
257-
// // console.log('unknown log', log.topics[0])
258-
// return null
259-
// // throw new Error('unknown log')
247+
// constructor(height: number) {
248+
// this.#height = height
260249
// }
261-
// }
262-
263-
type What = {
264-
// tokens: Set<string>,
265-
// collections: EnMap<CE>,
266-
// items: ItemStateUpdate[],
267-
}
268250

269-
export async function whatToDoWithTokens(x: What, ctx: Context) {
270-
// // ctx.store.findBy(CE, {id: In([...collectionMap.keys()])})
271-
// const knownTokens = await findByIdListAsMap(ctx.store, NE, tokens)
272-
// const events: EventEntity[] = []
273-
// for (const item of items) {
274-
// logger.debug(`APPLY ${item.interaction} on ${item.id}`)
275-
// let knownToken = knownTokens.get(item.id) ?? create(NE, item.id, {})
276-
// if (item.applyFrom) {
277-
// const collection = collections.get(item.contract)!
278-
// item.applyFrom(collection)
279-
// }
280-
// if (item.applyTo) {
281-
// knownToken = item.applyTo(knownToken)
282-
// }
283-
// events.push(item.event)
284-
// knownTokens.set(item.id, knownToken)
285-
// }
286-
// const values = [...knownTokens.values()]
287-
// await ctx.store.upsert(values)
288-
// await ctx.store.save(events)
289-
// return knownTokens
290-
}
251+
// get height() {
252+
// return this.#height
253+
// }
291254

292-
type EnMap<T> = Map<string, T>
293-
// TODO: do only if event was mint.
294-
async function completeTokens(ctx: Context, tokenMap: EnMap<NE>) {
295-
// const collections = groupedItemsByCollection(tokenMap.keys())
296-
// const final: NE[] = []
297-
// const metadataFutures: Promise<Optional<MetadataEntity>>[] = []
298-
// for (const [contract, ids] of collections.entries()) {
299-
// const list = Array.from(ids)
300-
// const tokens = await multicallMetadataFetch(ctx, contract, list)
301-
// for (const [i, id] of list.entries()) {
302-
// const realId = createTokenId(contract, id)
303-
// const token = tokenMap.get(realId)!
304-
// if (!token.metadata) {
305-
// const metadata = tokens[i]
306-
// token.metadata = metadata
307-
// const getMeta = handleMetadata(metadata, ctx.store).then(m => {
308-
// if (m) {
309-
// token.meta = m
310-
// token.name = m.name
311-
// token.image = m.image
312-
// token.media = m.animationUrl
313-
// }
314-
// return m
315-
// })
316-
// metadataFutures.push(getMeta)
317-
// final.push(token)
318-
// }
319-
// }
320-
// }
321-
// const metaList = await Promise.all(metadataFutures)
322-
// const filtered = metaList.filter(m => m) as MetadataEntity[]
323-
// logger.debug(`Saving ${filtered.length} metadata`)
324-
// await ctx.store.save(filtered)
325-
// await ctx.store.save(final)
326-
// return final
327-
// }
328-
// async function multicallMetadataFetch(ctx: Context, collection: string, tokens: Array<string>): Promise<string[]> {
329-
// const tokenIds = tokens.map((id) => [BigInt(id)])
330-
// const contract = new Multicall(ctx, lastBatchBlock(ctx), MULTICALL_ADDRESS)
331-
// const metadata = await contract.aggregate(
332-
// erc721.functions.tokenURI,
333-
// collection,
334-
// tokenIds,
335-
// MULTICALL_BATCH_SIZE
336-
// )
337-
// return metadata
338-
}
255+
// set height(height: number) {
256+
// this.#height = height
257+
// }
258+
// }

src/mappings/nfts/buy.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export async function handleTokenBuy(context: Context): Promise<void> {
2626
const originalPrice = event.price
2727
const originalOwner = entity.currentOwner ?? undefined
2828

29-
entity.price = BigInt(0)
29+
entity.price = null
3030
entity.currentOwner = event.caller
3131
entity.updatedAt = event.timestamp
3232

src/mappings/nfts/create.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getOrCreate } from '@kodadot1/metasquid/entity'
22
import md5 from 'md5'
3-
import { CollectionEntity as CE } from '../../model'
3+
import { CollectionEntity as CE, Kind } from '../../model'
44
import { handleMetadata } from '../shared/metadata'
55
import { unwrap } from '../utils/extract'
66
import { debug, pending, success } from '../utils/logger'
@@ -50,6 +50,7 @@ export async function handleCollectionCreate(context: Context): Promise<void> {
5050
final.name = metadata?.name
5151
final.image = metadata?.image
5252
final.media = metadata?.animationUrl
53+
final.kind = metadata?.kind || Kind.mixed
5354
}
5455

5556
success(OPERATION, `[COLLECTION] ${final.id}`)

src/mappings/nfts/list.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export async function handleTokenList(context: Context): Promise<void> {
2323
const id = createTokenId(event.collectionId, event.sn)
2424
const entity = await getWith(context.store, NE, id, { collection: true })
2525

26-
entity.price = event.price
26+
entity.price = Boolean(event.price) ? event.price : null
2727

2828
if (event.price && (entity.collection.floor === 0n || event.price < entity.collection.floor)) {
2929
entity.collection.floor = event.price

src/mappings/nfts/mint.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export async function handleTokenCreate(context: Context): Promise<void> {
4343
final.collection = collection
4444
final.sn = BigInt(event.sn)
4545
final.metadata = event.metadata || tokenUri(collection.baseUri, event.sn) || collection.metadata
46-
final.price = BigInt(0)
46+
final.price = null
4747
final.burned = false
4848
final.createdAt = event.timestamp
4949
final.updatedAt = event.timestamp

src/mappings/nfts/transfer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export async function handleTokenTransfer(context: Context): Promise<void> {
4141
const entity = await getWith(context.store, NE, id, { collection: true })
4242

4343
const oldOwner = entity.currentOwner
44-
entity.price = BigInt(0)
44+
entity.price = null
4545
entity.currentOwner = event.to
4646
entity.updatedAt = event.timestamp
4747

src/mappings/shared/metadata.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Optional } from '@kodadot1/metasquid/types'
33

44
import type { Content } from '@kodadot1/hyperdata'
55
import { logger } from '@kodadot1/metasquid/logger'
6-
import { MetadataEntity as Metadata } from '../../model/generated'
6+
import { Kind, MetadataEntity as Metadata } from '../../model/generated'
77
import { isEmpty } from '../utils/helper'
88
import { fetchMetadata } from '../utils/metadata'
99
import { Store, attributeFrom } from '../utils/types'
@@ -31,6 +31,7 @@ export async function handleMetadata(id: string, store: Store): Promise<Optional
3131
name: metadata.name || '',
3232
type: metadata.type || '',
3333
banner: metadata.banner || '',
34+
kind: metadata.kind as Kind || Kind.mixed,
3435
}
3536

3637
const final = create<Metadata>(Metadata, id, partial)

src/mappings/uniques/buy.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export async function handleTokenBuy(context: Context): Promise<void> {
2626
const originalPrice = event.price
2727
const originalOwner = entity.currentOwner ?? undefined
2828

29-
entity.price = BigInt(0)
29+
entity.price = null
3030
entity.currentOwner = event.caller
3131
entity.updatedAt = event.timestamp
3232

src/mappings/uniques/create.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getOrCreate } from '@kodadot1/metasquid/entity'
22
import md5 from 'md5'
3-
import { CollectionEntity as CE } from '../../model'
3+
import { CollectionEntity as CE, Kind } from '../../model'
44
import { handleMetadata } from '../shared/metadata'
55
import { unwrap } from '../utils/extract'
66
import { debug, pending, success } from '../utils/logger'
@@ -50,6 +50,7 @@ export async function handleCollectionCreate(context: Context): Promise<void> {
5050
final.name = metadata?.name
5151
final.image = metadata?.image
5252
final.media = metadata?.animationUrl
53+
final.kind = metadata?.kind || Kind.mixed
5354
}
5455

5556
success(OPERATION, `[COLLECTION] ${final.id}`)

src/mappings/uniques/list.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export async function handleTokenList(context: Context): Promise<void> {
2323
const id = createTokenId(event.collectionId, event.sn)
2424
const entity = await getWith(context.store, NE, id, { collection: true })
2525

26-
entity.price = event.price
26+
entity.price = Boolean(event.price) ? event.price : null
2727

2828
if (event.price && (entity.collection.floor === 0n || event.price < entity.collection.floor)) {
2929
entity.collection.floor = event.price

src/mappings/uniques/mint.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export async function handleTokenCreate(context: Context): Promise<void> {
4343
final.collection = collection
4444
final.sn = BigInt(event.sn)
4545
final.metadata = event.metadata || collection.metadata
46-
final.price = BigInt(0)
46+
final.price = null
4747
final.burned = false
4848
final.createdAt = event.timestamp
4949
final.updatedAt = event.timestamp

src/mappings/uniques/transfer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export async function handleTokenTransfer(context: Context): Promise<void> {
2424
const entity = await getWith(context.store, NE, id, { collection: true })
2525

2626
const oldOwner = entity.currentOwner
27-
entity.price = BigInt(0)
27+
entity.price = null
2828
entity.currentOwner = event.to
2929
entity.updatedAt = event.timestamp
3030

0 commit comments

Comments
 (0)