Skip to content

Commit

Permalink
feat: tests for handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
0xkenj1 committed Oct 22, 2024
1 parent 775fad8 commit 30c3eaf
Show file tree
Hide file tree
Showing 13 changed files with 723 additions and 40 deletions.
2 changes: 1 addition & 1 deletion packages/indexer-client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*"]
"include": ["src/**/*", "test/**/*"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { isAlloNativeToken } from "@grants-stack-indexer/shared";

import type { IEventHandler, ProcessorDependencies, StrategyTimings } from "../../internal.js";
import { getRoundRoles } from "../../helpers/roles.js";
import { RoundMetadataSchema } from "../../helpers/schemas.js";
import { extractStrategyFromId, getStrategyTimings } from "../../helpers/strategy.js";
import { calculateAmountInUsd } from "../../helpers/tokenMath.js";
import { TokenPriceNotFoundError } from "../../internal.js";
import { RoundMetadataSchema } from "../../schemas/index.js";

type Dependencies = Pick<
ProcessorDependencies,
Expand Down
2 changes: 2 additions & 0 deletions packages/processors/src/registry/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./profileCreated.hanlder.js";
export * from "./roleGranted.handler.js";
113 changes: 110 additions & 3 deletions packages/processors/src/registry/handlers/profileCreated.hanlder.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Changeset } from "@grants-stack-indexer/repository";
import { getAddress } from "viem";

import { Changeset, ProjectType } from "@grants-stack-indexer/repository";
import { ChainId, ProtocolEvent } from "@grants-stack-indexer/shared";

import { IEventHandler, ProcessorDependencies } from "../../internal.js";
import { ProjectMetadata, ProjectMetadataSchema } from "../../schemas/projectMetadata.js";

type Dependencies = Pick<
ProcessorDependencies,
"projectRepository" | "evmProvider" | "pricingProvider"
"projectRepository" | "evmProvider" | "pricingProvider" | "metadataProvider"
>;

export class ProfileCreatedHandler implements IEventHandler<"Registry", "ProfileCreated"> {
Expand All @@ -15,6 +18,110 @@ export class ProfileCreatedHandler implements IEventHandler<"Registry", "Profile
private dependencies: Dependencies,
) {}
async handle(): Promise<Changeset[]> {
return [];
const profileId = this.event.params.profileId;
const metadataCid = this.event.params.metadata[1];
const metadata = await this.dependencies.metadataProvider.getMetadata(metadataCid);

const parsedMetadata = ProjectMetadataSchema.safeParse(metadata);

let projectType: ProjectType = "canonical";
let isProgram = false;
let metadataValue = null;

if (parsedMetadata.success) {
projectType = this.getProjectTypeFromMetadata(parsedMetadata.data);
isProgram = parsedMetadata.data.type === "program";
metadataValue = parsedMetadata.data;
} else {
//TODO: Replace with logger
console.warn({
msg: `ProfileCreated: Failed to parse metadata for profile ${profileId}`,
event: this.event,
metadataCid,
metadata,
});
}

const tx = await this.dependencies.evmProvider.getTransaction(
this.event.transactionFields.hash,
);

const createdBy = tx.from;
const programTags = isProgram ? ["program"] : [];

const changes: Changeset[] = [
{
type: "InsertProject",
args: {
project: {
tags: ["allo-v2", ...programTags],
chainId: this.chainId,
registryAddress: getAddress(this.event.srcAddress),
id: profileId,
name: this.event.params.name,
nonce: this.event.params.nonce,
anchorAddress: getAddress(this.event.params.anchor),
projectNumber: null,
metadataCid: metadataCid,
metadata: metadataValue,
createdByAddress: getAddress(createdBy),
createdAtBlock: BigInt(this.event.blockNumber),
updatedAtBlock: BigInt(this.event.blockNumber),
projectType,
},
},
},
{
type: "InsertProjectRole",
args: {
projectRole: {
chainId: this.chainId,
projectId: this.event.params.profileId,
address: getAddress(this.event.params.owner),
role: "owner",
createdAtBlock: BigInt(this.event.blockNumber),
},
},
},
];

const pendingProjectRoles =
await this.dependencies.projectRepository.getPendingProjectRolesByRole(
this.chainId,
profileId,
);

if (pendingProjectRoles.length !== 0) {
for (const role of pendingProjectRoles) {
changes.push({
type: "InsertProjectRole",
args: {
projectRole: {
chainId: this.chainId,
projectId: profileId,
address: getAddress(role.address),
role: "member",
createdAtBlock: BigInt(this.event.blockNumber),
},
},
});
}

changes.push({
type: "DeletePendingProjectRoles",
args: { ids: pendingProjectRoles.map((r) => r.id!) },
});
}

return changes;
}

private getProjectTypeFromMetadata(metadata: ProjectMetadata): ProjectType {
// if the metadata contains a canonical reference, it's a linked project
if ("canonical" in metadata) {
return "linked";
}

return "canonical";
}
}
26 changes: 21 additions & 5 deletions packages/processors/src/registry/registry.processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,33 @@ import { Changeset } from "@grants-stack-indexer/repository";
import { ChainId, ProtocolEvent, RegistryEvent } from "@grants-stack-indexer/shared";

import type { IProcessor } from "../internal.js";
import { UnsupportedEventException } from "../internal.js";
import { ProcessorDependencies } from "../types/processor.types.js";
import { RegistryHandlerFactory } from "./registryProcessorFactory.js";
import { ProfileCreatedHandler, RoleGrantedHandler } from "./handlers/index.js";

export class RegistryProcessor implements IProcessor<"Registry", RegistryEvent> {
private factory: RegistryHandlerFactory = new RegistryHandlerFactory();
constructor(
private readonly chainId: ChainId,
private readonly dependencies: ProcessorDependencies,
) {}
//TODO: Implement
async process(_event: ProtocolEvent<"Registry", RegistryEvent>): Promise<Changeset[]> {
return await this.factory.createHandler(_event, this.chainId, this.dependencies).handle();

async process(event: ProtocolEvent<"Registry", RegistryEvent>): Promise<Changeset[]> {
//TODO: Implement robust error handling and retry logic
switch (event.eventName) {
case "RoleGranted":
return new RoleGrantedHandler(
event as ProtocolEvent<"Registry", "RoleGranted">,
this.chainId,
this.dependencies,
).handle();
case "ProfileCreated":
return new ProfileCreatedHandler(
event as ProtocolEvent<"Registry", "ProfileCreated">,
this.chainId,
this.dependencies,
).handle();
default:
throw new UnsupportedEventException("Registry", event.eventName);
}
}
}
25 changes: 0 additions & 25 deletions packages/processors/src/registry/registryProcessorFactory.ts

This file was deleted.

2 changes: 2 additions & 0 deletions packages/processors/src/schemas/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./projectMetadata.js";
export * from "./roundMetadata.js";
30 changes: 30 additions & 0 deletions packages/processors/src/schemas/projectMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { z } from "zod";

export const ProjectMetadataSchema = z.union([
z
.object({
title: z.string(),
description: z.string(),
})
.passthrough()
.transform((data) => ({ type: "project" as const, ...data })),
z
.object({
canonical: z.object({
registryAddress: z.string(),
chainId: z.coerce.number(),
}),
})
.transform((data) => ({ type: "project" as const, ...data })),
z.object({
type: z.literal("program"),
name: z.string(),
}),
z
.object({
name: z.string(),
})
.transform((data) => ({ type: "program" as const, ...data })),
]);

export type ProjectMetadata = z.infer<typeof ProjectMetadataSchema>;
File renamed without changes.
5 changes: 0 additions & 5 deletions packages/processors/test/index.spec.ts

This file was deleted.

Loading

0 comments on commit 30c3eaf

Please sign in to comment.