Skip to content

Commit

Permalink
refactor to events query
Browse files Browse the repository at this point in the history
  • Loading branch information
doerfli committed Nov 15, 2024
1 parent 0e6d89f commit d20d7c6
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 109 deletions.
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export const DUNE_QUERY_ID_BASE_LATEST_BLOCK = process.env.DUNE_QUERY_ID_BASE_LA
export const DUNE_QUERY_ID_NFT_REGISTRATION_EVENTS = process.env.DUNE_QUERY_ID_NFT_REGISTRATION_EVENTS || "4283531";
export const DUNE_QUERY_ID_NFT_TRANSFER_EVENTS = process.env.DUNE_QUERY_ID_NFT_TRANSFER_EVENTS || "4283862";
export const DUNE_QUERY_ID_INSTANCE_SERVICE_EVENTS = process.env.DUNE_QUERY_ID_INSTANCE_SERVICE_EVENTS || "4284748";
export const DUNE_QUERY_ID_GIF_EVENTS = process.env.DUNE_QUERY_ID_GIF_EVENTS || "4287183";
9 changes: 8 additions & 1 deletion src/dune.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,16 @@ export default class DuneApi {
if (totalRowCount === 0) {
totalRowCount = response.data.result.metadata.total_row_count;
}
const rowCount = response.data.result.metadata.row_count;
if (rowCount === 0) {
break;
}
if (rowCount !== response.data.result.rows.length) {
throw new Error(`Row count mismatch expected: ${rowCount} effective: ${response.data.result.rows.length}`);
}
rows.push(...response.data.result.rows);
offset += limit;
} while (totalRowCount > 0 && offset * limit < totalRowCount)
} while (totalRowCount > 0 && offset < totalRowCount)

logger.info(`Fetched ${rows.length} rows`);

Expand Down
66 changes: 50 additions & 16 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { PrismaClient } from '@prisma/client';
import axios from 'axios';
import * as dotenv from 'dotenv';
import { DUNE_API_BASE_URL, DUNE_API_KEY, DUNE_QUERY_ID_INSTANCE_SERVICE_EVENTS, DUNE_QUERY_ID_NFT_REGISTRATION_EVENTS, DUNE_QUERY_ID_NFT_TRANSFER_EVENTS } from './constants';
import { DUNE_API_BASE_URL, DUNE_API_KEY, DUNE_QUERY_ID_GIF_EVENTS, DUNE_QUERY_ID_INSTANCE_SERVICE_EVENTS, DUNE_QUERY_ID_NFT_REGISTRATION_EVENTS, DUNE_QUERY_ID_NFT_TRANSFER_EVENTS } from './constants';
import InstanceProcessor from './instance_processor';
import { logger } from './logger';
import NftProcessor from './nft_processor';
import { ObjectType } from './types/objecttype';
import DuneApi from './dune';
import { DecodedLogEntry } from './types/logdata';
import { Nft } from './types/nft';
import { Instance } from './types/instance';

dotenv.config();

Expand All @@ -29,28 +32,59 @@ class Main {
}

public async main(): Promise<void> {
const nftRegistrationEvents = await this.dune.getLatestResult(DUNE_QUERY_ID_NFT_REGISTRATION_EVENTS, 0);
const nftTransferEvents = await this.dune.getLatestResult(DUNE_QUERY_ID_NFT_TRANSFER_EVENTS, 0);
const gifEvents = await this.dune.getLatestResult(DUNE_QUERY_ID_GIF_EVENTS, 0);
const { nfts, instances } = await this.parseGifEvents(gifEvents);
// const nftTransferEvents = await this.dune.getLatestResult(DUNE_QUERY_ID_NFT_TRANSFER_EVENTS, 0);

let nfts = await this.nftProcessor.processNftRegistrationEvents(nftRegistrationEvents);
nfts = await this.nftProcessor.processNftTransferEvents(nftTransferEvents, nfts);
await this.nftProcessor.persistNfts(nfts);
// let nfts = await this.nftProcessor.processNftRegistrationEvents(nftRegistrationEvents);
// nfts = await this.nftProcessor.processNftTransferEvents(nftTransferEvents, nfts);
// await this.nftProcessor.persistNfts(nfts);

// print one log per event
nfts.forEach(event => {
logger.info(`NFT: ${event.nftId} - ${ObjectType[event.objectType]} - ${event.objectAddress} - ${event.owner}`);
});
// // print one log per event
const nftIterator = nfts.values();

for (const nft of nftIterator) {
logger.info(`NFT: ${nft.nftId} - ${ObjectType[nft.objectType]} - ${nft.objectAddress} - ${nft.owner}`);
};

const instanceEvents = await this.dune.getLatestResult(DUNE_QUERY_ID_INSTANCE_SERVICE_EVENTS, 0);
const instances = await this.instanceProcessor.processInstanceServiceEvents(instanceEvents);
await this.instanceProcessor.persistInstances(instances);
// const instanceEvents = await this.dune.getLatestResult(DUNE_QUERY_ID_INSTANCE_SERVICE_EVENTS, 0);
// const instances = await this.instanceProcessor.processInstanceServiceEvents(instanceEvents);
// await this.instanceProcessor.persistInstances(instances);

// print one log per event
instances.forEach(event => {
logger.info(`Instance: ${event.nftId} - ${event.instanceAddress}`);
});
// instances.forEach(event => {
// logger.info(`Instance: ${event.nftId} - ${event.instanceAddress}`);
// });
}

async parseGifEvents(gifEvents: Array<DecodedLogEntry>)
: Promise<{ nfts: Map<BigInt, Nft>, instances: Map<BigInt, Instance> }>
{
const nfts = new Map<BigInt, Nft>();
const instances = new Map<BigInt, Instance>();
// TODO const policies = new Map<BigInt, Policy>();

for (const event of gifEvents) {
logger.debug(`Processing gif event ${event.tx_hash} - ${event.block_number} - ${event.event_name}`);

switch (event.event_name) {
case 'Transfer':
await this.nftProcessor.processNftTransferEvent(event, nfts);
break;
case 'LogRegistryObjectRegistered':
await this.nftProcessor.processNftRegistrationEvent(event, nfts);
break;
// // Transfer
// // LogRegistryObjectRegistered
// // LogInstanceServiceInstanceCreated
// // LogApplicationServiceApplicationCreated
// // LogPolicyServicePolicyCreated
// // LogPolicyServicePolicyPremiumCollected
}
}

return { nfts, instances };
}
}

const prisma = new PrismaClient()
Expand Down
117 changes: 71 additions & 46 deletions src/nft_processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { logger } from "./logger";
import { IRegistry__factory } from "./generated/contracts/gif";
import { DecodedLogEntry } from "./types/logdata";
import { Nft } from "./types/nft";
import { log } from "console";

export default class NftProcessor {
private prisma: PrismaClient;
Expand Down Expand Up @@ -42,25 +43,76 @@ export default class NftProcessor {
}
}

async processNftRegistrationEvents(nftRegistrationEvents: Array<DecodedLogEntry>): Promise<Array<Nft>> {
return nftRegistrationEvents.map(event => {
logger.info(`Processing nft registration event ${event.tx_hash} - ${event.event_name} - ${event.data}`);
const data = this.decodeLogRegistryObjectRegisteredEvent(event);
if (data === null || data === undefined) {
logger.error(`Failed to decode event ${event.tx_hash} - ${event.event_name} - ${event.data}`);
return null as unknown as Nft;
async processNftRegistrationEvent(event: DecodedLogEntry, nfts: Map<BigInt, Nft>): Promise<Map<BigInt, Nft>> {
if (event.event_name !== 'LogRegistryObjectRegistered') {
throw new Error(`Invalid event type ${event.event_name}`);
}

logger.info(`Processing nft registration event ${event.tx_hash} - ${event.event_name} - ${event.data}`);
const data = this.decodeLogRegistryObjectRegisteredEvent(event);
if (data === null || data === undefined) {
logger.error(`Failed to decode event ${event.tx_hash} - ${event.event_name} - ${event.data}`);
return nfts;
}

const nftId = data.args[0] as BigInt;
const parentNftId = data.args[1] as BigInt;
const objectType = getObjectType(BigInt(data.args[2]));
const objectAddress = data.args[4] as string;
const owner = data.args[5] as string;
const nft = {
nftId,
parentNftId,
objectType: objectType,
objectAddress: objectAddress,
owner: owner,
created: {
blockNumber: event.block_number,
txHash: event.tx_hash,
from: event.tx_from
},
modified: {
blockNumber: event.block_number,
txHash: event.tx_hash,
from: event.tx_from
}
const nftId = data.args[0] as BigInt;
const parentNftId = data.args[1] as BigInt;
const objectType = getObjectType(BigInt(data.args[2]));
const objectAddress = data.args[4] as string;
const owner = data.args[5] as string;
return {
} as Nft;
nfts.set(nftId, nft);
return nfts;
}

async processNftTransferEvent(event: DecodedLogEntry, nfts: Map<BigInt, Nft>): Promise<Map<BigInt, Nft>> {
if (event.event_name !== 'Transfer') {
throw new Error(`Invalid event type ${event.event_name}`);
}

const from = `0x${event.topic1.substring(26)}`;
const to = `0x${event.topic2.substring(26)}`;
const nftId = BigInt(event.topic3);

if (nfts.has(nftId) && from === '0x0000000000000000000000000000000000000000') {
logger.debug(`Initial nft event transfer ${nftId}`);
} else if (nfts.has(nftId)) {
logger.debug(`Transfer event from known nft ${nftId} from ${from} to ${to}`);
const nft = nfts.get(nftId);
if (nft === undefined) {
logger.error(`NFT ${nftId} not found for update`);
return nfts;
}
nft.owner = to;
nft.modified = {
blockNumber: event.block_number,
txHash: event.tx_hash,
from: event.tx_from
};
} else {
logger.debug(`Transfer event from unknown nft ${nftId} from ${from} to ${to}`);
const nft = {
nftId,
parentNftId,
objectType: objectType,
objectAddress: objectAddress,
owner: owner,
parentNftId: BigInt(0),
objectType: ObjectType.UNKNOWN,
objectAddress: '',
owner: to,
created: {
blockNumber: event.block_number,
txHash: event.tx_hash,
Expand All @@ -71,36 +123,9 @@ export default class NftProcessor {
txHash: event.tx_hash,
from: event.tx_from
}
} as Nft;
}).filter(event => event !== null);
}

async processNftTransferEvents(nftTransferEvents: Array<DecodedLogEntry>, nfts: Array<Nft>): Promise<Array<Nft>> {
nftTransferEvents.forEach(event => {
logger.debug(`Processing nft transfer event ${event.tx_hash} - ${event.event_name} - ${event.topic0} - ${event.topic1} - ${event.topic2} - ${event.topic3} - ${event.data}`);
// extract addresses
const from = `0x${event.topic1.substring(26)}`;
const to = `0x${event.topic2.substring(26)}`;
const nftId = BigInt(event.topic3);
// logger.debug(`Transfer from ${from} to ${to} for NFT ${nftId}`);

if (from === '0x0000000000000000000000000000000000000000') {
return;
}

const nft = nfts.find(nft => nft.nftId === nftId);
if (nft === undefined) {
logger.error(`NFT ${nftId} not found`);
return;
}
nft.owner = to;
nft.modified = {
blockNumber: event.block_number,
txHash: event.tx_hash,
from: event.tx_from
};
logger.debug(`Transfer NFT ${nftId} from ${from} to ${to}`);
});
nfts.set(nftId, nft);
}
return nfts;
}

Expand Down
49 changes: 3 additions & 46 deletions src/types/objecttype.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { logger } from "../logger";

export enum ObjectType {
UNKNOWN,
PROTOCOL,
REGISTRY,
STAKING,
Expand Down Expand Up @@ -37,68 +38,24 @@ export enum ObjectType {
export function getObjectType(type: BigInt): ObjectType {
logger.debug(`getObjectType(${type})`);
switch (type) {
case BigInt(0):
return ObjectType.UNKNOWN;
case BigInt(1):
return ObjectType.PROTOCOL;
// case 2:
// return ObjectType.REGISTRY;
// case 3:
// return ObjectType.STAKING;
// case 6:
// return ObjectType.RELEASE;
// case 7:
// return ObjectType.ROLE;
case BigInt(8):
return ObjectType.SERVICE;
case BigInt(10):
return ObjectType.INSTANCE;
// case 11:
// return ObjectType.COMPONENT;
case BigInt(12):
return ObjectType.PRODUCT;
case BigInt(13):
return ObjectType.ORACLE;
// case 14:
// return ObjectType.DISTRIBUTION;
case BigInt(15):
return ObjectType.POOL;
// case 20:
// return ObjectType.APPLICATION;
case BigInt(21):
return ObjectType.POLICY;
case BigInt(22):
return ObjectType.BUNDLE;
// case 23:
// return ObjectType.DISTRIBUTOR;
// case 30:
// return ObjectType.STAKE;
// case 31:
// return ObjectType.TARGET;
// case 40:
// return ObjectType.ACCOUNTING;
// case 41:
// return ObjectType.FEE;
// case 42:
// return ObjectType.PRICE;
// case 43:
// return ObjectType.PREMIUM;
// case 44:
// return ObjectType.RISK;
// case 45:
// return ObjectType.CLAIM;
// case 46:
// return ObjectType.PAYOUT;
// case 47:
// return ObjectType.REQUEST;
// case 48:
// return ObjectType.DISTRIBUTOR_TYPE;
// case 49:
// return ObjectType.REFERRAL;
// case 97:
// return ObjectType.CORE;
// case 98:
// return ObjectType.CUSTOM;
// case 99:
// return ObjectType.ALL;
default:
throw new Error("Invalid ObjectType");
}
Expand Down

0 comments on commit d20d7c6

Please sign in to comment.