diff --git a/packages/data-flow/test/unit/eventsRegistry.spec.ts b/packages/data-flow/test/unit/eventsRegistry.spec.ts index 7a293f2..59920e4 100644 --- a/packages/data-flow/test/unit/eventsRegistry.spec.ts +++ b/packages/data-flow/test/unit/eventsRegistry.spec.ts @@ -48,7 +48,7 @@ describe("InMemoryEventsRegistry", () => { expect(retrievedEvent).toEqual(mockEvent); }); - it("should update the last processed event when saving multiple times", async () => { + it("updates the last processed event when saving multiple times", async () => { const registry = new InMemoryEventsRegistry(logger); const firstEvent: ProcessorEvent<"Allo", "PoolCreated"> = { diff --git a/packages/processors/src/exceptions/projectNotFound.exception.ts b/packages/processors/src/exceptions/projectNotFound.exception.ts index ba9d367..9ff64cd 100644 --- a/packages/processors/src/exceptions/projectNotFound.exception.ts +++ b/packages/processors/src/exceptions/projectNotFound.exception.ts @@ -5,3 +5,9 @@ export class ProjectNotFound extends Error { super(`Project not found for chainId: ${chainId} and anchorAddress: ${anchorAddress}`); } } + +export class ProjectByRoleNotFound extends Error { + constructor(chainId: ChainId, role: string) { + super(`Project not found for chainId: ${chainId} and role: ${role}`); + } +} diff --git a/packages/processors/src/internal.ts b/packages/processors/src/internal.ts index ec599c0..265ae03 100644 --- a/packages/processors/src/internal.ts +++ b/packages/processors/src/internal.ts @@ -6,8 +6,8 @@ export * from "./interfaces/index.js"; export * from "./exceptions/index.js"; // Allo -export * from "./allo/index.js"; +export * from "./processors/allo/index.js"; // Strategy -export * from "./strategy/index.js"; -export * from "./registry/index.js"; +export * from "./processors/strategy/index.js"; +export * from "./processors/registry/index.js"; diff --git a/packages/processors/src/allo/allo.processor.ts b/packages/processors/src/processors/allo/allo.processor.ts similarity index 86% rename from packages/processors/src/allo/allo.processor.ts rename to packages/processors/src/processors/allo/allo.processor.ts index 87430a0..fa783c8 100644 --- a/packages/processors/src/allo/allo.processor.ts +++ b/packages/processors/src/processors/allo/allo.processor.ts @@ -1,8 +1,8 @@ import { Changeset } from "@grants-stack-indexer/repository"; import { AlloEvent, ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; -import type { IProcessor, ProcessorDependencies } from "../internal.js"; -import { UnsupportedEventException } from "../internal.js"; +import type { IProcessor, ProcessorDependencies } from "../../internal.js"; +import { UnsupportedEventException } from "../../internal.js"; import { PoolCreatedHandler } from "./handlers/index.js"; /** diff --git a/packages/processors/src/allo/handlers/index.ts b/packages/processors/src/processors/allo/handlers/index.ts similarity index 100% rename from packages/processors/src/allo/handlers/index.ts rename to packages/processors/src/processors/allo/handlers/index.ts diff --git a/packages/processors/src/allo/handlers/poolCreated.handler.ts b/packages/processors/src/processors/allo/handlers/poolCreated.handler.ts similarity index 97% rename from packages/processors/src/allo/handlers/poolCreated.handler.ts rename to packages/processors/src/processors/allo/handlers/poolCreated.handler.ts index e1dc9ae..aed83db 100644 --- a/packages/processors/src/allo/handlers/poolCreated.handler.ts +++ b/packages/processors/src/processors/allo/handlers/poolCreated.handler.ts @@ -4,10 +4,10 @@ import type { Changeset, NewRound, PendingRoundRole } from "@grants-stack-indexe import type { ChainId, ProcessorEvent, Token } from "@grants-stack-indexer/shared"; import { getToken, isAlloNativeToken } from "@grants-stack-indexer/shared"; -import type { IEventHandler, ProcessorDependencies, StrategyTimings } from "../../internal.js"; -import { calculateAmountInUsd, getRoundRoles } from "../../helpers/index.js"; -import { StrategyHandlerFactory, TokenPriceNotFoundError } from "../../internal.js"; -import { RoundMetadataSchema } from "../../schemas/index.js"; +import type { IEventHandler, ProcessorDependencies, StrategyTimings } from "../../../internal.js"; +import { calculateAmountInUsd, getRoundRoles } from "../../../helpers/index.js"; +import { StrategyHandlerFactory, TokenPriceNotFoundError } from "../../../internal.js"; +import { RoundMetadataSchema } from "../../../schemas/index.js"; type Dependencies = Pick< ProcessorDependencies, diff --git a/packages/processors/src/allo/index.ts b/packages/processors/src/processors/allo/index.ts similarity index 100% rename from packages/processors/src/allo/index.ts rename to packages/processors/src/processors/allo/index.ts diff --git a/packages/processors/src/processors/registry/handlers/index.ts b/packages/processors/src/processors/registry/handlers/index.ts new file mode 100644 index 0000000..dd16069 --- /dev/null +++ b/packages/processors/src/processors/registry/handlers/index.ts @@ -0,0 +1,6 @@ +export * from "./profileCreated.handler.js"; +export * from "./profileMetadataUpdated.handler.js"; +export * from "./profileNameUpdated.handler.js"; +export * from "./profileOwnerUpdated.handler.js"; +export * from "./roleGranted.handler.js"; +export * from "./roleRevoked.handler.js"; diff --git a/packages/processors/src/registry/handlers/profileCreated.handler.ts b/packages/processors/src/processors/registry/handlers/profileCreated.handler.ts similarity index 89% rename from packages/processors/src/registry/handlers/profileCreated.handler.ts rename to packages/processors/src/processors/registry/handlers/profileCreated.handler.ts index bf3eaad..0fc5eb1 100644 --- a/packages/processors/src/registry/handlers/profileCreated.handler.ts +++ b/packages/processors/src/processors/registry/handlers/profileCreated.handler.ts @@ -3,8 +3,8 @@ import { getAddress } from "viem"; import { Changeset, ProjectType } from "@grants-stack-indexer/repository"; import { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; -import { IEventHandler, ProcessorDependencies } from "../../internal.js"; -import { ProjectMetadata, ProjectMetadataSchema } from "../../schemas/projectMetadata.js"; +import { IEventHandler, ProcessorDependencies } from "../../../internal.js"; +import { ProjectMetadata, ProjectMetadataSchema } from "../../../schemas/projectMetadata.js"; type Dependencies = Pick< ProcessorDependencies, @@ -12,6 +12,13 @@ type Dependencies = Pick< >; /** * Handles the ProfileCreated event for the Registry contract from Allo protocol. + * + * This handler performs the following steps: + * - Fetches the metadata for the profile from the metadata provider + * - Parses the metadata to extract the project type + * - Returns the changeset to insert the project with the metadata + * + * If the metadata is not valid, it sets the metadata to null and the project type to canonical. */ export class ProfileCreatedHandler implements IEventHandler<"Registry", "ProfileCreated"> { constructor( @@ -35,14 +42,6 @@ export class ProfileCreatedHandler implements IEventHandler<"Registry", "Profile projectType = this.getProjectTypeFromMetadata(parsedMetadata.data); isProgram = parsedMetadata.data.type === "program"; metadataValue = parsedMetadata.data; - } else { - //TODO: Replace with logger - // this.logger.warn({ - // msg: `ProfileCreated: Failed to parse metadata for profile ${profileId}`, - // event: this.event, - // metadataCid, - // metadata, - // }); } const createdBy = diff --git a/packages/processors/src/processors/registry/handlers/profileMetadataUpdated.handler.ts b/packages/processors/src/processors/registry/handlers/profileMetadataUpdated.handler.ts new file mode 100644 index 0000000..0da4627 --- /dev/null +++ b/packages/processors/src/processors/registry/handlers/profileMetadataUpdated.handler.ts @@ -0,0 +1,78 @@ +import { Changeset, ProjectType } from "@grants-stack-indexer/repository"; +import { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; + +import { IEventHandler, ProcessorDependencies } from "../../../internal.js"; +import { ProjectMetadata, ProjectMetadataSchema } from "../../../schemas/index.js"; + +type Dependencies = Pick< + ProcessorDependencies, + "projectRepository" | "evmProvider" | "metadataProvider" | "logger" +>; + +/** + * Handles the ProfileMetadataUpdated event for the Registry contract from Allo protocol. + * + * This handler performs the following steps: + * - Fetches the metadata for the profile from the metadata provider + * - Parses the metadata to extract the project type + * - Returns the changeset to update the project with the metadata + */ +export class ProfileMetadataUpdatedHandler + implements IEventHandler<"Registry", "ProfileMetadataUpdated"> +{ + constructor( + readonly event: ProcessorEvent<"Registry", "ProfileMetadataUpdated">, + readonly chainId: ChainId, + private dependencies: Dependencies, + ) {} + /* @inheritdoc */ + async handle(): Promise { + const { metadataProvider } = this.dependencies; + + const metadataCid = this.event.params.metadata[1]; + const metadata = await metadataProvider.getMetadata(metadataCid); + const parsedMetadata = ProjectMetadataSchema.safeParse(metadata); + + if (!parsedMetadata.success) { + return [ + { + type: "UpdateProject", + args: { + chainId: this.chainId, + projectId: this.event.params.profileId, + project: { + metadataCid: metadataCid, + metadata: null, + projectType: "canonical", + }, + }, + }, + ]; + } + + const projectType = this.getProjectTypeFromMetadata(parsedMetadata.data); + + return [ + { + type: "UpdateProject", + args: { + chainId: this.chainId, + projectId: this.event.params.profileId, + project: { + metadataCid: metadataCid, + metadata: metadata, + projectType, + }, + }, + }, + ]; + } + 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"; + } +} diff --git a/packages/processors/src/processors/registry/handlers/profileNameUpdated.handler.ts b/packages/processors/src/processors/registry/handlers/profileNameUpdated.handler.ts new file mode 100644 index 0000000..b246111 --- /dev/null +++ b/packages/processors/src/processors/registry/handlers/profileNameUpdated.handler.ts @@ -0,0 +1,37 @@ +import { getAddress } from "viem"; + +import { Changeset } from "@grants-stack-indexer/repository"; +import { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; + +import { IEventHandler, ProcessorDependencies } from "../../../internal.js"; + +type Dependencies = Pick; +/** + * Handles the ProfileNameUpdated event for the Registry contract from Allo protocol. + * + * This handler performs the following steps: + * - Returns the changeset to update the project with the new name + */ +export class ProfileNameUpdatedHandler implements IEventHandler<"Registry", "ProfileNameUpdated"> { + constructor( + readonly event: ProcessorEvent<"Registry", "ProfileNameUpdated">, + readonly chainId: ChainId, + private dependencies: Dependencies, + ) {} + /* @inheritdoc */ + async handle(): Promise { + return [ + { + type: "UpdateProject", + args: { + chainId: this.chainId, + projectId: this.event.params.profileId, + project: { + name: this.event.params.name, + anchorAddress: getAddress(this.event.params.anchor), + }, + }, + }, + ]; + } +} diff --git a/packages/processors/src/processors/registry/handlers/profileOwnerUpdated.handler.ts b/packages/processors/src/processors/registry/handlers/profileOwnerUpdated.handler.ts new file mode 100644 index 0000000..45fefca --- /dev/null +++ b/packages/processors/src/processors/registry/handlers/profileOwnerUpdated.handler.ts @@ -0,0 +1,52 @@ +import { getAddress } from "viem"; + +import { Changeset } from "@grants-stack-indexer/repository"; +import { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; + +import { IEventHandler, ProcessorDependencies } from "../../../internal.js"; + +type Dependencies = Pick; +/** + * Handles the ProfileOwnerUpdated event for the Registry contract from Allo protocol. + * + * This handler performs the following steps: + * + * - Returns the changeset to delete all project roles with the role "owner" + * for the profile and insert a new project role with the new owner address. + */ +export class ProfileOwnerUpdatedHandler + implements IEventHandler<"Registry", "ProfileOwnerUpdated"> +{ + constructor( + readonly event: ProcessorEvent<"Registry", "ProfileOwnerUpdated">, + readonly chainId: ChainId, + private dependencies: Dependencies, + ) {} + /* @inheritdoc */ + async handle(): Promise { + return [ + { + type: "DeleteAllProjectRolesByRole", + args: { + projectRole: { + chainId: this.chainId, + projectId: this.event.params.profileId, + role: "owner", + }, + }, + }, + { + 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), + }, + }, + }, + ]; + } +} diff --git a/packages/processors/src/registry/handlers/roleGranted.handler.ts b/packages/processors/src/processors/registry/handlers/roleGranted.handler.ts similarity index 94% rename from packages/processors/src/registry/handlers/roleGranted.handler.ts rename to packages/processors/src/processors/registry/handlers/roleGranted.handler.ts index 461043e..2308eee 100644 --- a/packages/processors/src/registry/handlers/roleGranted.handler.ts +++ b/packages/processors/src/processors/registry/handlers/roleGranted.handler.ts @@ -3,8 +3,8 @@ import { getAddress } from "viem"; import { Changeset } from "@grants-stack-indexer/repository"; import { ALLO_OWNER_ROLE, ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; -import { IEventHandler } from "../../internal.js"; -import { ProcessorDependencies } from "../../types/processor.types.js"; +import { IEventHandler } from "../../../internal.js"; +import { ProcessorDependencies } from "../../../types/processor.types.js"; /** * Handles the RoleGranted event for the Registry contract from Allo protocol. diff --git a/packages/processors/src/processors/registry/handlers/roleRevoked.handler.ts b/packages/processors/src/processors/registry/handlers/roleRevoked.handler.ts new file mode 100644 index 0000000..a6154bc --- /dev/null +++ b/packages/processors/src/processors/registry/handlers/roleRevoked.handler.ts @@ -0,0 +1,53 @@ +import { getAddress } from "viem"; + +import { Changeset } from "@grants-stack-indexer/repository"; +import { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; + +import { IEventHandler, ProcessorDependencies, ProjectByRoleNotFound } from "../../../internal.js"; + +type Dependencies = Pick; +/** + * Handles the RoleRevoked event for the Registry contract from Allo protocol. + * + * This handler performs the following steps: + * + * - Returns the changeset to delete all project roles with the role "member" + * for the profile and address. + * + * If the project with the role id doesn't exist, it throws an error. + */ +export class RoleRevokedHandler implements IEventHandler<"Registry", "RoleRevoked"> { + constructor( + readonly event: ProcessorEvent<"Registry", "RoleRevoked">, + readonly chainId: ChainId, + private dependencies: Dependencies, + ) {} + /* @inheritdoc */ + async handle(): Promise { + const { projectRepository } = this.dependencies; + const account = getAddress(this.event.params.account); + const role = this.event.params.role.toLowerCase(); + const project = await projectRepository.getProjectById(this.chainId, role); + + // The role value for a member is the profileId in Allo V1 + // which is the project id in this database. + // If we don't find a project with that id we can't remove the role. + if (!project) { + throw new ProjectByRoleNotFound(this.chainId, role); + } + + return [ + { + type: "DeleteAllProjectRolesByRoleAndAddress", + args: { + projectRole: { + chainId: this.chainId, + projectId: project.id, + address: account, + role: "member", + }, + }, + }, + ]; + } +} diff --git a/packages/processors/src/registry/index.ts b/packages/processors/src/processors/registry/index.ts similarity index 100% rename from packages/processors/src/registry/index.ts rename to packages/processors/src/processors/registry/index.ts diff --git a/packages/processors/src/processors/registry/registry.processor.ts b/packages/processors/src/processors/registry/registry.processor.ts new file mode 100644 index 0000000..07ba60c --- /dev/null +++ b/packages/processors/src/processors/registry/registry.processor.ts @@ -0,0 +1,66 @@ +import { Changeset } from "@grants-stack-indexer/repository"; +import { ChainId, ProcessorEvent, 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 { + ProfileCreatedHandler, + ProfileMetadataUpdatedHandler, + ProfileNameUpdatedHandler, + ProfileOwnerUpdatedHandler, + RoleGrantedHandler, + RoleRevokedHandler, +} from "./handlers/index.js"; + +export class RegistryProcessor implements IProcessor<"Registry", RegistryEvent> { + constructor( + private readonly chainId: ChainId, + private readonly dependencies: ProcessorDependencies, + ) {} + + async process(event: ProcessorEvent<"Registry", RegistryEvent>): Promise { + //TODO: Implement robust error handling and retry logic + switch (event.eventName) { + case "ProfileCreated": + return new ProfileCreatedHandler( + event as ProcessorEvent<"Registry", "ProfileCreated">, + this.chainId, + this.dependencies, + ).handle(); + case "ProfileMetadataUpdated": + return new ProfileMetadataUpdatedHandler( + event as ProcessorEvent<"Registry", "ProfileMetadataUpdated">, + this.chainId, + this.dependencies, + ).handle(); + case "ProfileNameUpdated": + return new ProfileNameUpdatedHandler( + event as ProcessorEvent<"Registry", "ProfileNameUpdated">, + this.chainId, + this.dependencies, + ).handle(); + case "ProfileOwnerUpdated": + return new ProfileOwnerUpdatedHandler( + event as ProcessorEvent<"Registry", "ProfileOwnerUpdated">, + this.chainId, + this.dependencies, + ).handle(); + case "RoleGranted": + return new RoleGrantedHandler( + event as ProcessorEvent<"Registry", "RoleGranted">, + this.chainId, + this.dependencies, + ).handle(); + case "RoleRevoked": + return new RoleRevokedHandler( + event as ProcessorEvent<"Registry", "RoleRevoked">, + this.chainId, + this.dependencies, + ).handle(); + + default: + throw new UnsupportedEventException("Registry", event.eventName); + } + } +} diff --git a/packages/processors/src/strategy/common/base.strategy.ts b/packages/processors/src/processors/strategy/common/base.strategy.ts similarity index 94% rename from packages/processors/src/strategy/common/base.strategy.ts rename to packages/processors/src/processors/strategy/common/base.strategy.ts index 83fcc7b..e7bed16 100644 --- a/packages/processors/src/strategy/common/base.strategy.ts +++ b/packages/processors/src/processors/strategy/common/base.strategy.ts @@ -1,7 +1,7 @@ import { Changeset } from "@grants-stack-indexer/repository"; import { Address, ProcessorEvent, StrategyEvent, Token } from "@grants-stack-indexer/shared"; -import { IStrategyHandler, StrategyTimings } from "../../internal.js"; +import { IStrategyHandler, StrategyTimings } from "../../../internal.js"; /** * @abstract diff --git a/packages/processors/src/strategy/common/baseDistributed.handler.ts b/packages/processors/src/processors/strategy/common/baseDistributed.handler.ts similarity index 95% rename from packages/processors/src/strategy/common/baseDistributed.handler.ts rename to packages/processors/src/processors/strategy/common/baseDistributed.handler.ts index b80225b..d938130 100644 --- a/packages/processors/src/strategy/common/baseDistributed.handler.ts +++ b/packages/processors/src/processors/strategy/common/baseDistributed.handler.ts @@ -3,7 +3,7 @@ import { getAddress } from "viem"; import { Changeset } from "@grants-stack-indexer/repository"; import { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; -import { IEventHandler, ProcessorDependencies } from "../../internal.js"; +import { IEventHandler, ProcessorDependencies } from "../../../internal.js"; type Dependencies = Pick; diff --git a/packages/processors/src/strategy/common/index.ts b/packages/processors/src/processors/strategy/common/index.ts similarity index 100% rename from packages/processors/src/strategy/common/index.ts rename to packages/processors/src/processors/strategy/common/index.ts diff --git a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts similarity index 97% rename from packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts rename to packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts index b167224..81302eb 100644 --- a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts +++ b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts @@ -9,10 +9,10 @@ import { Token, } from "@grants-stack-indexer/shared"; -import type { ProcessorDependencies, StrategyTimings } from "../../internal.js"; -import DonationVotingMerkleDistributionDirectTransferStrategy from "../../abis/allo-v2/v1/DonationVotingMerkleDistributionDirectTransferStrategy.js"; -import { calculateAmountInUsd, getDateFromTimestamp } from "../../helpers/index.js"; -import { TokenPriceNotFoundError, UnsupportedEventException } from "../../internal.js"; +import type { ProcessorDependencies, StrategyTimings } from "../../../internal.js"; +import DonationVotingMerkleDistributionDirectTransferStrategy from "../../../abis/allo-v2/v1/DonationVotingMerkleDistributionDirectTransferStrategy.js"; +import { calculateAmountInUsd, getDateFromTimestamp } from "../../../helpers/index.js"; +import { TokenPriceNotFoundError, UnsupportedEventException } from "../../../internal.js"; import { BaseDistributedHandler, BaseStrategyHandler } from "../common/index.js"; import { DVMDAllocatedHandler, DVMDRegisteredHandler } from "./handlers/index.js"; diff --git a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.ts b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.ts similarity index 98% rename from packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.ts rename to packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.ts index 888badf..5960914 100644 --- a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.ts +++ b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.ts @@ -3,7 +3,7 @@ import { Address, encodePacked, getAddress, keccak256 } from "viem"; import { Application, Changeset, Donation, Round } from "@grants-stack-indexer/repository"; import { ChainId, getToken, ProcessorEvent, Token } from "@grants-stack-indexer/shared"; -import { getTokenAmountInUsd, getUsdInTokenAmount } from "../../../helpers/index.js"; +import { getTokenAmountInUsd, getUsdInTokenAmount } from "../../../../helpers/index.js"; import { ApplicationNotFound, IEventHandler, @@ -11,8 +11,8 @@ import { ProcessorDependencies, RoundNotFound, UnknownToken, -} from "../../../internal.js"; -import { ApplicationMetadata, ApplicationMetadataSchema } from "../../../schemas/index.js"; +} from "../../../../internal.js"; +import { ApplicationMetadata, ApplicationMetadataSchema } from "../../../../schemas/index.js"; type Dependencies = Pick< ProcessorDependencies, diff --git a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.ts b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.ts similarity index 100% rename from packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.ts rename to packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.ts diff --git a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.ts b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.ts similarity index 99% rename from packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.ts rename to packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.ts index 99cd2a0..9250ca6 100644 --- a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.ts +++ b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.ts @@ -8,7 +8,7 @@ import { ProcessorDependencies, ProjectNotFound, RoundNotFound, -} from "../../../internal.js"; +} from "../../../../internal.js"; import { decodeDVMDApplicationData } from "../helpers/index.js"; type Dependencies = Pick< diff --git a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.ts b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.ts similarity index 100% rename from packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.ts rename to packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.ts diff --git a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/index.ts b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/index.ts similarity index 100% rename from packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/index.ts rename to packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/index.ts diff --git a/packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/types/index.ts b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/types/index.ts similarity index 100% rename from packages/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/types/index.ts rename to packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/types/index.ts diff --git a/packages/processors/src/strategy/index.ts b/packages/processors/src/processors/strategy/index.ts similarity index 100% rename from packages/processors/src/strategy/index.ts rename to packages/processors/src/processors/strategy/index.ts diff --git a/packages/processors/src/strategy/mapping.ts b/packages/processors/src/processors/strategy/mapping.ts similarity index 96% rename from packages/processors/src/strategy/mapping.ts rename to packages/processors/src/processors/strategy/mapping.ts index 9913bf2..98eb429 100644 --- a/packages/processors/src/strategy/mapping.ts +++ b/packages/processors/src/processors/strategy/mapping.ts @@ -1,6 +1,6 @@ import { Hex } from "viem"; -import type { StrategyHandlerConstructor } from "../internal.js"; +import type { StrategyHandlerConstructor } from "../../internal.js"; import { DVMDDirectTransferStrategyHandler } from "./donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.js"; /** diff --git a/packages/processors/src/strategy/strategy.processor.ts b/packages/processors/src/processors/strategy/strategy.processor.ts similarity index 86% rename from packages/processors/src/strategy/strategy.processor.ts rename to packages/processors/src/processors/strategy/strategy.processor.ts index c41557e..035e91b 100644 --- a/packages/processors/src/strategy/strategy.processor.ts +++ b/packages/processors/src/processors/strategy/strategy.processor.ts @@ -1,8 +1,8 @@ import { Changeset } from "@grants-stack-indexer/repository"; import { ChainId, ProcessorEvent, StrategyEvent } from "@grants-stack-indexer/shared"; -import type { IProcessor, ProcessorDependencies } from "../internal.js"; -import { UnsupportedStrategy } from "../internal.js"; +import type { IProcessor, ProcessorDependencies } from "../../internal.js"; +import { UnsupportedStrategy } from "../../internal.js"; import { StrategyHandlerFactory } from "./strategyHandler.factory.js"; export class StrategyProcessor implements IProcessor<"Strategy", StrategyEvent> { diff --git a/packages/processors/src/strategy/strategyHandler.factory.ts b/packages/processors/src/processors/strategy/strategyHandler.factory.ts similarity index 97% rename from packages/processors/src/strategy/strategyHandler.factory.ts rename to packages/processors/src/processors/strategy/strategyHandler.factory.ts index 7b466db..357ffc0 100644 --- a/packages/processors/src/strategy/strategyHandler.factory.ts +++ b/packages/processors/src/processors/strategy/strategyHandler.factory.ts @@ -2,7 +2,7 @@ import { Hex } from "viem"; import { ChainId, StrategyEvent } from "@grants-stack-indexer/shared"; -import { getHandler, IStrategyHandler, ProcessorDependencies } from "../internal.js"; +import { getHandler, IStrategyHandler, ProcessorDependencies } from "../../internal.js"; /** * Factory for creating strategy handlers diff --git a/packages/processors/src/registry/handlers/index.ts b/packages/processors/src/registry/handlers/index.ts deleted file mode 100644 index 59fea08..0000000 --- a/packages/processors/src/registry/handlers/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./profileCreated.handler.js"; -export * from "./roleGranted.handler.js"; diff --git a/packages/processors/src/registry/registry.processor.ts b/packages/processors/src/registry/registry.processor.ts deleted file mode 100644 index b23ab6c..0000000 --- a/packages/processors/src/registry/registry.processor.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Changeset } from "@grants-stack-indexer/repository"; -import { ChainId, ProcessorEvent, 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 { ProfileCreatedHandler, RoleGrantedHandler } from "./handlers/index.js"; - -export class RegistryProcessor implements IProcessor<"Registry", RegistryEvent> { - constructor( - private readonly chainId: ChainId, - private readonly dependencies: ProcessorDependencies, - ) {} - - async process(event: ProcessorEvent<"Registry", RegistryEvent>): Promise { - //TODO: Implement robust error handling and retry logic - switch (event.eventName) { - case "RoleGranted": - return new RoleGrantedHandler( - event as ProcessorEvent<"Registry", "RoleGranted">, - this.chainId, - this.dependencies, - ).handle(); - case "ProfileCreated": - return new ProfileCreatedHandler( - event as ProcessorEvent<"Registry", "ProfileCreated">, - this.chainId, - this.dependencies, - ).handle(); - default: - throw new UnsupportedEventException("Registry", event.eventName); - } - } -} diff --git a/packages/processors/test/allo/allo.processor.spec.ts b/packages/processors/test/allo/allo.processor.spec.ts index e1a3617..95fee3b 100644 --- a/packages/processors/test/allo/allo.processor.spec.ts +++ b/packages/processors/test/allo/allo.processor.spec.ts @@ -10,12 +10,12 @@ import type { } from "@grants-stack-indexer/repository"; import type { AlloEvent, ChainId, ILogger, ProcessorEvent } from "@grants-stack-indexer/shared"; -import { AlloProcessor } from "../../src/allo/allo.processor.js"; -import { PoolCreatedHandler } from "../../src/allo/handlers/poolCreated.handler.js"; import { UnsupportedEventException } from "../../src/internal.js"; +import { AlloProcessor } from "../../src/processors/allo/allo.processor.js"; +import { PoolCreatedHandler } from "../../src/processors/allo/handlers/poolCreated.handler.js"; // Mock the handlers -vi.mock("../../src/allo/handlers/poolCreated.handler.js", () => { +vi.mock("../../src/processors/allo/handlers/poolCreated.handler.js", () => { const PoolCreatedHandler = vi.fn(); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access PoolCreatedHandler.prototype.handle = vi.fn(); diff --git a/packages/processors/test/allo/handlers/poolCreated.handler.spec.ts b/packages/processors/test/allo/handlers/poolCreated.handler.spec.ts index b508ca5..a5e1dfb 100644 --- a/packages/processors/test/allo/handlers/poolCreated.handler.spec.ts +++ b/packages/processors/test/allo/handlers/poolCreated.handler.spec.ts @@ -11,7 +11,7 @@ import { mergeDeep } from "@grants-stack-indexer/shared"; import { PoolCreatedHandler, TIMESTAMP_DELTA_RANGE, -} from "../../../src/allo/handlers/poolCreated.handler.js"; +} from "../../../src/processors/allo/handlers/poolCreated.handler.js"; // Function to create a mock event with optional overrides function createMockEvent( diff --git a/packages/processors/test/helpers/tokenMath.spec.ts b/packages/processors/test/helpers/tokenMath.spec.ts index 33a8736..fc79e97 100644 --- a/packages/processors/test/helpers/tokenMath.spec.ts +++ b/packages/processors/test/helpers/tokenMath.spec.ts @@ -33,7 +33,7 @@ describe("calculateAmountInUsd", () => { }); // Test case for 8 decimal token with float price - it("should correctly calculate USD amount for 8 decimal token with float price", () => { + it("correctly calculates USD amount for 8 decimal token with float price", () => { const amount = 150000000n; // 1.5 tokens const tokenPriceInUsd = 12.75; // $12.75 per token const tokenDecimals = 8; @@ -89,7 +89,7 @@ describe("calculateAmountInUsd", () => { expect(result).toBe("0"); }); - it("should return zero for zero token price", () => { + it("returns zero for zero token price", () => { const amount = 1000000000000000000n; // 1 token const tokenPriceInUsd = 0; const tokenDecimals = 18; diff --git a/packages/processors/test/registry/handlers/profileCreated.handler.spec.ts b/packages/processors/test/registry/handlers/profileCreated.handler.spec.ts index 0ec6c3d..9c3bb2d 100644 --- a/packages/processors/test/registry/handlers/profileCreated.handler.spec.ts +++ b/packages/processors/test/registry/handlers/profileCreated.handler.spec.ts @@ -12,7 +12,7 @@ import { import { Bytes32String, ChainId, ILogger, ProcessorEvent } from "@grants-stack-indexer/shared"; import { ProcessorDependencies } from "../../../src/internal.js"; -import { ProfileCreatedHandler } from "../../../src/registry/handlers/index.js"; +import { ProfileCreatedHandler } from "../../../src/processors/registry/handlers/index.js"; describe("ProfileCreatedHandler", () => { let mockEvent: ProcessorEvent<"Registry", "ProfileCreated">; diff --git a/packages/processors/test/registry/handlers/profileMetadataUpdated.handler.spec.ts b/packages/processors/test/registry/handlers/profileMetadataUpdated.handler.spec.ts new file mode 100644 index 0000000..7404bf2 --- /dev/null +++ b/packages/processors/test/registry/handlers/profileMetadataUpdated.handler.spec.ts @@ -0,0 +1,92 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; + +import { ProcessorDependencies } from "../../../src/internal.js"; +import { ProfileMetadataUpdatedHandler } from "../../../src/processors/registry/handlers/profileMetadataUpdated.handler.js"; + +describe("ProfileMetadataUpdatedHandler", () => { + const mockCid = "mockCid"; + const mockEvent: ProcessorEvent<"Registry", "ProfileMetadataUpdated"> = { + params: { + metadata: [0, mockCid], + profileId: "mockProfileId", + }, + } as ProcessorEvent<"Registry", "ProfileMetadataUpdated">; + + const mockDependencies = { + metadataProvider: { + getMetadata: vi.fn(), + }, + logger: { + warn: vi.fn(), + }, + } as unknown as ProcessorDependencies; + + const chainId = 1 as ChainId; + + afterEach(() => { + vi.resetAllMocks(); + }); + + it("handles valid metadata", async () => { + const mockMetadata = { + type: "program", + name: "Test Project", + }; + vi.spyOn(mockDependencies.metadataProvider, "getMetadata").mockResolvedValueOnce( + mockMetadata, + ); + + const handler = new ProfileMetadataUpdatedHandler(mockEvent, chainId, mockDependencies); + const result = await handler.handle(); + + expect(mockDependencies.metadataProvider.getMetadata).toHaveBeenCalledWith(mockCid); + expect(result).toEqual([ + { + type: "UpdateProject", + args: { + chainId, + projectId: mockEvent.params.profileId, + project: { + metadataCid: mockCid, + metadata: mockMetadata, + projectType: "canonical", + }, + }, + }, + ]); + }); + + it("returns an empty array for invalid metadata", async () => { + vi.spyOn(mockDependencies.metadataProvider, "getMetadata").mockResolvedValueOnce(null); + + const handler = new ProfileMetadataUpdatedHandler(mockEvent, chainId, mockDependencies); + const result = await handler.handle(); + + expect(result).toEqual([ + { + type: "UpdateProject", + args: { + chainId, + projectId: mockEvent.params.profileId, + project: { + metadataCid: mockCid, + metadata: null, + projectType: "canonical", + }, + }, + }, + ]); + }); + + it("throws an error if getMetadata fails", async () => { + vi.spyOn(mockDependencies.metadataProvider, "getMetadata").mockRejectedValueOnce( + new Error("Failed to fetch metadata"), + ); + + const handler = new ProfileMetadataUpdatedHandler(mockEvent, chainId, mockDependencies); + + await expect(handler.handle()).rejects.toThrow("Failed to fetch metadata"); + }); +}); diff --git a/packages/processors/test/registry/handlers/profileNameUpdated.handler.spec.ts b/packages/processors/test/registry/handlers/profileNameUpdated.handler.spec.ts new file mode 100644 index 0000000..68230b2 --- /dev/null +++ b/packages/processors/test/registry/handlers/profileNameUpdated.handler.spec.ts @@ -0,0 +1,57 @@ +import { getAddress } from "viem"; +import { describe, expect, it, vi } from "vitest"; + +import { Changeset } from "@grants-stack-indexer/repository"; +import { Bytes32String, ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; + +import { ProfileNameUpdatedHandler } from "../../../src/processors/registry/handlers/profileNameUpdated.handler.js"; + +describe("ProfileNameUpdatedHandler", () => { + const mockEvent: ProcessorEvent<"Registry", "ProfileNameUpdated"> = { + contractName: "Registry", + eventName: "ProfileNameUpdated", + params: { + profileId: "0xprofile1" as Bytes32String, + name: "New Profile Name", + anchor: "0x5aD1D85Bb68791Cb3cE598f56E00F5D5694FAd14", + }, + blockNumber: 1, + blockTimestamp: 1, + chainId: 1 as ChainId, + logIndex: 1, + srcAddress: "0x0", + transactionFields: { + hash: "0x0", + transactionIndex: 1, + }, + }; + + it("returns a changeset with updated project name and anchor address", async () => { + const handler = new ProfileNameUpdatedHandler(mockEvent, 1 as ChainId, { + logger: { + debug: vi.fn(), + error: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + }, + }); + + const result = await handler.handle(); + + const expectedChangeset: Changeset[] = [ + { + type: "UpdateProject", + args: { + chainId: mockEvent.chainId as ChainId, + projectId: mockEvent.params.profileId, + project: { + name: mockEvent.params.name, + anchorAddress: getAddress(mockEvent.params.anchor), + }, + }, + }, + ]; + + expect(result).toEqual(expectedChangeset); + }); +}); diff --git a/packages/processors/test/registry/handlers/profileOwnerUpdated.handler.spec.ts b/packages/processors/test/registry/handlers/profileOwnerUpdated.handler.spec.ts new file mode 100644 index 0000000..396ad2e --- /dev/null +++ b/packages/processors/test/registry/handlers/profileOwnerUpdated.handler.spec.ts @@ -0,0 +1,72 @@ +import { describe, expect, it, vi } from "vitest"; + +import { Changeset } from "@grants-stack-indexer/repository"; +import { Bytes32String, ChainId, ProcessorEvent } from "@grants-stack-indexer/shared"; + +import { ProfileOwnerUpdatedHandler } from "../../../src/processors/registry/handlers/profileOwnerUpdated.handler.js"; + +describe("ProfileOwnerUpdatedHandler", () => { + it("handles ProfileOwnerUpdated event correctly", async () => { + const mockEvent: ProcessorEvent<"Registry", "ProfileOwnerUpdated"> = { + blockNumber: 123456, + blockTimestamp: 123456, + chainId: 1 as ChainId, + contractName: "Registry", + eventName: "ProfileOwnerUpdated", + logIndex: 0, + srcAddress: "0x1234567890123456789012345678901234567890", + params: { + profileId: "0xprofile123" as Bytes32String, + owner: "0x5aD1D85Bb68791Cb3cE598f56E00F5D5694FAd14", + }, + transactionFields: { + hash: "0xhash", + transactionIndex: 0, + }, + }; + + const mockDependencies = { + logger: { + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + debug: vi.fn(), + }, + }; + + const handler = new ProfileOwnerUpdatedHandler( + mockEvent, + mockEvent.chainId as ChainId, + mockDependencies, + ); + + const result = await handler.handle(); + + const expectedChangeset: Changeset[] = [ + { + type: "DeleteAllProjectRolesByRole", + args: { + projectRole: { + chainId: mockEvent.chainId as ChainId, + projectId: mockEvent.params.profileId, + role: "owner", + }, + }, + }, + { + type: "InsertProjectRole", + args: { + projectRole: { + chainId: mockEvent.chainId as ChainId, + projectId: mockEvent.params.profileId, + address: mockEvent.params.owner, + role: "owner", + createdAtBlock: BigInt(mockEvent.blockNumber), + }, + }, + }, + ]; + + expect(result).toEqual(expectedChangeset); + }); +}); diff --git a/packages/processors/test/registry/handlers/roleGranted.handler.spec.ts b/packages/processors/test/registry/handlers/roleGranted.handler.spec.ts index 72f23c4..1a7aaa4 100644 --- a/packages/processors/test/registry/handlers/roleGranted.handler.spec.ts +++ b/packages/processors/test/registry/handlers/roleGranted.handler.spec.ts @@ -9,7 +9,7 @@ import { } from "@grants-stack-indexer/shared"; import { ProcessorDependencies } from "../../../src/internal.js"; -import { RoleGrantedHandler } from "../../../src/registry/handlers/index.js"; // Adjust path if needed +import { RoleGrantedHandler } from "../../../src/processors/registry/handlers/index.js"; describe("RoleGrantedHandler", () => { const mockProjectRepository = { diff --git a/packages/processors/test/registry/handlers/roleRevoked.handler.spec.ts b/packages/processors/test/registry/handlers/roleRevoked.handler.spec.ts new file mode 100644 index 0000000..a602ad2 --- /dev/null +++ b/packages/processors/test/registry/handlers/roleRevoked.handler.spec.ts @@ -0,0 +1,83 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { IProjectRepository, Project } from "@grants-stack-indexer/repository"; +import { ChainId, ILogger, ProcessorEvent } from "@grants-stack-indexer/shared"; + +import { ProjectByRoleNotFound } from "../../../src/internal.js"; +import { RoleRevokedHandler } from "../../../src/processors/registry/handlers/roleRevoked.handler.js"; + +describe("RoleRevokedHandler", () => { + let mockEvent: ProcessorEvent<"Registry", "RoleRevoked">; + let mockChainId: ChainId; + let mockDependencies: { projectRepository: IProjectRepository; logger: ILogger }; + let mockedRole: string; + let mockedAccount: string; + + beforeEach(() => { + mockedRole = "0x5aD1D85Bb68791Cb3cE598f56E00F5D5694FAd14ASD"; + mockedAccount = "0x5aD1D85Bb68791Cb3cE598f56E00F5D5694FAd14"; + mockEvent = { + params: { + account: mockedAccount, + role: mockedRole, + }, + } as ProcessorEvent<"Registry", "RoleRevoked">; + + mockChainId = 1 as ChainId; + + mockDependencies = { + projectRepository: { + getProjectById: vi.fn(), + } as unknown as IProjectRepository, + logger: { + info: vi.fn(), + } as unknown as ILogger, + }; + }); + + it("return a changeset when project is found", async () => { + const project = { id: "project-1" }; + vi.spyOn(mockDependencies.projectRepository, "getProjectById").mockResolvedValueOnce({ + ...project, + } as Project); + + const handler = new RoleRevokedHandler(mockEvent, mockChainId, mockDependencies); + const result = await handler.handle(); + + expect(result).toEqual([ + { + type: "DeleteAllProjectRolesByRoleAndAddress", + args: { + projectRole: { + chainId: mockChainId, + projectId: project.id, + address: mockedAccount, + role: "member", + }, + }, + }, + ]); + }); + + it("return an empty array when project is not found", async () => { + vi.spyOn(mockDependencies.projectRepository, "getProjectById").mockResolvedValueOnce( + undefined, + ); + + const handler = new RoleRevokedHandler(mockEvent, mockChainId, mockDependencies); + + await expect(handler.handle()).rejects.toThrow(ProjectByRoleNotFound); + }); + + it("throw an error when getProjectById fails", async () => { + const error = new ProjectByRoleNotFound( + mockEvent.chainId as ChainId, + mockEvent.params.role, + ); + vi.spyOn(mockDependencies.projectRepository, "getProjectById").mockRejectedValueOnce(error); + + const handler = new RoleRevokedHandler(mockEvent, mockChainId, mockDependencies); + + await expect(handler.handle()).rejects.toThrow(error); + }); +}); diff --git a/packages/processors/test/registry/registry.processor.spec.ts b/packages/processors/test/registry/registry.processor.spec.ts index c26647c..321e0b1 100644 --- a/packages/processors/test/registry/registry.processor.spec.ts +++ b/packages/processors/test/registry/registry.processor.spec.ts @@ -3,12 +3,16 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import type { ChainId, ProcessorEvent, RegistryEvent } from "@grants-stack-indexer/shared"; import { ProcessorDependencies, UnsupportedEventException } from "../../src/internal.js"; -import { ProfileCreatedHandler } from "../../src/registry/handlers/profileCreated.handler.js"; -import { RoleGrantedHandler } from "../../src/registry/handlers/roleGranted.handler.js"; -import { RegistryProcessor } from "../../src/registry/registry.processor.js"; +import { ProfileCreatedHandler } from "../../src/processors/registry/handlers/profileCreated.handler.js"; +import { ProfileMetadataUpdatedHandler } from "../../src/processors/registry/handlers/profileMetadataUpdated.handler.js"; +import { ProfileNameUpdatedHandler } from "../../src/processors/registry/handlers/profileNameUpdated.handler.js"; +import { ProfileOwnerUpdatedHandler } from "../../src/processors/registry/handlers/profileOwnerUpdated.handler.js"; +import { RoleGrantedHandler } from "../../src/processors/registry/handlers/roleGranted.handler.js"; +import { RoleRevokedHandler } from "../../src/processors/registry/handlers/roleRevoked.handler.js"; +import { RegistryProcessor } from "../../src/processors/registry/registry.processor.js"; // Mock the handlers and their handle methods -vi.mock("../../src/registry/handlers/roleGranted.handler.js", () => { +vi.mock("../../src/processors/registry/handlers/roleGranted.handler.js", () => { const RoleGrantedHandler = vi.fn(); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access RoleGrantedHandler.prototype.handle = vi.fn(); @@ -17,8 +21,7 @@ vi.mock("../../src/registry/handlers/roleGranted.handler.js", () => { }; }); -// Mock the handlers and their handle methods -vi.mock("../../src/registry/handlers/profileCreated.handler.js", () => { +vi.mock("../../src/processors/registry/handlers/profileCreated.handler.js", () => { const ProfileCreatedHandler = vi.fn(); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access ProfileCreatedHandler.prototype.handle = vi.fn(); @@ -27,6 +30,40 @@ vi.mock("../../src/registry/handlers/profileCreated.handler.js", () => { }; }); +vi.mock("../../src/processors/registry/handlers/profileOwnerUpdated.handler.js", () => { + const ProfileOwnerUpdatedHandler = vi.fn(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + ProfileOwnerUpdatedHandler.prototype.handle = vi.fn(); + return { + ProfileOwnerUpdatedHandler, + }; +}); + +vi.mock("../../src/processors/registry/handlers/roleRevoked.handler.js", () => { + const RoleRevokedHandler = vi.fn(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + RoleRevokedHandler.prototype.handle = vi.fn(); + return { + RoleRevokedHandler, + }; +}); +vi.mock("../../src/processors/registry/handlers/profileMetadataUpdated.handler.js", () => { + const ProfileMetadataUpdatedHandler = vi.fn(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + ProfileMetadataUpdatedHandler.prototype.handle = vi.fn(); + return { + ProfileMetadataUpdatedHandler, + }; +}); +vi.mock("../../src/processors/registry/handlers/profileNameUpdated.handler.js", () => { + const ProfileNameUpdatedHandler = vi.fn(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + ProfileNameUpdatedHandler.prototype.handle = vi.fn(); + return { + ProfileNameUpdatedHandler, + }; +}); + describe("RegistryProcessor", () => { const chainId: ChainId = 10 as ChainId; // Replace with appropriate chainId const dependencies: ProcessorDependencies = {} as ProcessorDependencies; // Replace with actual dependencies @@ -45,7 +82,7 @@ describe("RegistryProcessor", () => { await expect(processor.process(event)).rejects.toThrow(UnsupportedEventException); }); - it("should call ProfileCreatedHandler", async () => { + it("calls ProfileCreatedHandler", async () => { const event: ProcessorEvent<"Registry", "ProfileCreated"> = { eventName: "ProfileCreated", } as ProcessorEvent<"Registry", "ProfileCreated">; @@ -59,7 +96,7 @@ describe("RegistryProcessor", () => { expect(result).toEqual([]); // Check if handle returns [] }); - it("should call RoleGrantedHandler", async () => { + it("calls RoleGrantedHandler", async () => { const event: ProcessorEvent<"Registry", "RoleGranted"> = { eventName: "RoleGranted", } as ProcessorEvent<"Registry", "RoleGranted">; @@ -72,4 +109,56 @@ describe("RegistryProcessor", () => { expect(RoleGrantedHandler.prototype.handle).toHaveBeenCalled(); expect(result).toEqual([]); // Check if handle returns [] }); + it("calls ProfileOwnerUpdatedHandler", async () => { + const event: ProcessorEvent<"Registry", "ProfileOwnerUpdated"> = { + eventName: "ProfileOwnerUpdated", + } as ProcessorEvent<"Registry", "ProfileOwnerUpdated">; + + vi.spyOn(ProfileOwnerUpdatedHandler.prototype, "handle").mockResolvedValue([]); + + const processor = new RegistryProcessor(chainId, dependencies); + const result = await processor.process(event); + + expect(ProfileOwnerUpdatedHandler.prototype.handle).toHaveBeenCalled(); + expect(result).toEqual([]); // Check if handle returns [] + }); + it("calls RoleRevokedHandler", async () => { + const event: ProcessorEvent<"Registry", "RoleRevoked"> = { + eventName: "RoleRevoked", + } as ProcessorEvent<"Registry", "RoleRevoked">; + + vi.spyOn(RoleRevokedHandler.prototype, "handle").mockResolvedValue([]); + + const processor = new RegistryProcessor(chainId, dependencies); + const result = await processor.process(event); + + expect(RoleRevokedHandler.prototype.handle).toHaveBeenCalled(); + expect(result).toEqual([]); // Check if handle returns [] + }); + it("calls ProfileMetadataUpdatedHandler", async () => { + const event: ProcessorEvent<"Registry", "ProfileMetadataUpdated"> = { + eventName: "ProfileMetadataUpdated", + } as ProcessorEvent<"Registry", "ProfileMetadataUpdated">; + + vi.spyOn(ProfileMetadataUpdatedHandler.prototype, "handle").mockResolvedValue([]); + + const processor = new RegistryProcessor(chainId, dependencies); + const result = await processor.process(event); + + expect(ProfileMetadataUpdatedHandler.prototype.handle).toHaveBeenCalled(); + expect(result).toEqual([]); // Check if handle returns [] + }); + it("calls ProfileNameUpdatedHandler", async () => { + const event: ProcessorEvent<"Registry", "ProfileNameUpdated"> = { + eventName: "ProfileNameUpdated", + } as ProcessorEvent<"Registry", "ProfileNameUpdated">; + + vi.spyOn(ProfileNameUpdatedHandler.prototype, "handle").mockResolvedValue([]); + + const processor = new RegistryProcessor(chainId, dependencies); + const result = await processor.process(event); + + expect(ProfileNameUpdatedHandler.prototype.handle).toHaveBeenCalled(); + expect(result).toEqual([]); // Check if handle returns [] + }); }); diff --git a/packages/processors/test/strategy/common/base.strategy.spec.ts b/packages/processors/test/strategy/common/base.strategy.spec.ts index 7ff9c51..2ec4086 100644 --- a/packages/processors/test/strategy/common/base.strategy.spec.ts +++ b/packages/processors/test/strategy/common/base.strategy.spec.ts @@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest"; import { Changeset } from "@grants-stack-indexer/repository"; import { Address, Token, TokenCode } from "@grants-stack-indexer/shared"; -import { BaseStrategyHandler } from "../../../src/strategy/common/base.strategy.js"; +import { BaseStrategyHandler } from "../../../src/processors/strategy/common/base.strategy.js"; // Create a concrete implementation of BaseStrategyHandler for testing class TestStrategyHandler extends BaseStrategyHandler { diff --git a/packages/processors/test/strategy/common/baseDistributed.handler.spec.ts b/packages/processors/test/strategy/common/baseDistributed.handler.spec.ts index 4d19ac7..a774933 100644 --- a/packages/processors/test/strategy/common/baseDistributed.handler.spec.ts +++ b/packages/processors/test/strategy/common/baseDistributed.handler.spec.ts @@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { IRoundReadRepository, Round } from "@grants-stack-indexer/repository"; import { ChainId, ILogger, ProcessorEvent } from "@grants-stack-indexer/shared"; -import { BaseDistributedHandler } from "../../../src/strategy/common/baseDistributed.handler.js"; +import { BaseDistributedHandler } from "../../../src/processors/strategy/common/baseDistributed.handler.js"; function createMockEvent( overrides: Partial> = {}, diff --git a/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.spec.ts b/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.spec.ts index 41fdd83..540420f 100644 --- a/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.spec.ts +++ b/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.spec.ts @@ -19,15 +19,15 @@ import { } from "@grants-stack-indexer/shared"; import { TokenPriceNotFoundError, UnsupportedEventException } from "../../../src/internal.js"; -import { BaseDistributedHandler } from "../../../src/strategy/common/index.js"; -import { DVMDDirectTransferStrategyHandler } from "../../../src/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.js"; +import { BaseDistributedHandler } from "../../../src/processors/strategy/common/index.js"; +import { DVMDDirectTransferStrategyHandler } from "../../../src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.js"; import { DVMDAllocatedHandler, DVMDRegisteredHandler, -} from "../../../src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.js"; +} from "../../../src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.js"; vi.mock( - "../../../src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.js", + "../../../src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.js", () => { const DVMDRegisteredHandler = vi.fn(); const DVMDAllocatedHandler = vi.fn(); @@ -41,7 +41,7 @@ vi.mock( }; }, ); -vi.mock("../../../src/strategy/common/baseDistributed.handler.js", () => { +vi.mock("../../../src/processors/strategy/common/baseDistributed.handler.js", () => { const BaseDistributedHandler = vi.fn(); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access BaseDistributedHandler.prototype.handle = vi.fn(); diff --git a/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.spec.ts b/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.spec.ts index 3523787..04360fd 100644 --- a/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.spec.ts +++ b/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.spec.ts @@ -17,7 +17,7 @@ import { TokenPriceNotFoundError, UnknownToken, } from "../../../../src/exceptions/index.js"; -import { DVMDAllocatedHandler } from "../../../../src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.js"; +import { DVMDAllocatedHandler } from "../../../../src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.js"; function createMockEvent( overrides: DeepPartial> = {}, diff --git a/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.spec.ts b/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.spec.ts index c76b4a1..74bf6e0 100644 --- a/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.spec.ts +++ b/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.spec.ts @@ -11,7 +11,7 @@ import { import { ChainId, DeepPartial, mergeDeep, ProcessorEvent } from "@grants-stack-indexer/shared"; import { ProjectNotFound, RoundNotFound } from "../../../../src/exceptions/index.js"; -import { DVMDRegisteredHandler } from "../../../../src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.js"; +import { DVMDRegisteredHandler } from "../../../../src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.js"; function createMockEvent( overrides: DeepPartial> = {}, diff --git a/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.spec.ts b/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.spec.ts index 51aa787..7bfdfc7 100644 --- a/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.spec.ts +++ b/packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.spec.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from "vitest"; -import { decodeDVMDApplicationData } from "../../../../src/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.js"; -import { DVMDApplicationData } from "../../../../src/strategy/donationVotingMerkleDistributionDirectTransfer/types/index.js"; +import { decodeDVMDApplicationData } from "../../../../src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.js"; +import { DVMDApplicationData } from "../../../../src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/types/index.js"; describe("decodeDVMDApplicationData", () => { - it("should correctly decode the encoded data", () => { + it("correctly decodes the encoded data", () => { const encodedData = "0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000002c7296a5ec0539f0a018c7176c97c92a9c44e2b4000000000000000000000000e7eb5d2b5b188777df902e89c54570e7ef4f59ce000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000003b6261666b72656967796334336366696e786c6e6168713561617773676869626574763675737273376b6b78663776786d7a626a79726f37366977790000000000"; diff --git a/packages/processors/test/strategy/mapping.spec.ts b/packages/processors/test/strategy/mapping.spec.ts index caa64a0..913bd82 100644 --- a/packages/processors/test/strategy/mapping.spec.ts +++ b/packages/processors/test/strategy/mapping.spec.ts @@ -2,11 +2,11 @@ import { describe, expect, expectTypeOf, it } from "vitest"; import { existsHandler } from "../../src/external.js"; import { getHandler, StrategyHandlerConstructor } from "../../src/internal.js"; -import { DVMDDirectTransferStrategyHandler } from "../../src/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.js"; +import { DVMDDirectTransferStrategyHandler } from "../../src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.js"; describe("Strategy Mapping", () => { describe("getHandler", () => { - it("should return the correct handler for a valid strategy ID", () => { + it("returns the correct handler for a valid strategy ID", () => { const validStrategyId = "0x6f9291df02b2664139cec5703c124e4ebce32879c74b6297faa1468aa5ff9ebf"; @@ -17,7 +17,7 @@ describe("Strategy Mapping", () => { expectTypeOf(handler).toEqualTypeOf(); }); - it("should return the correct handler for a valid strategy ID in uppercase", () => { + it("returns the correct handler for a valid strategy ID in uppercase", () => { const validStrategyId = "0x6F9291DF02B2664139CEC5703C124E4EBCE32879C74B6297FAA1468AA5FF9EBF"; @@ -28,7 +28,7 @@ describe("Strategy Mapping", () => { expectTypeOf(handler).toEqualTypeOf(); }); - it("should return undefined for an invalid strategy ID", () => { + it("returns undefined for an invalid strategy ID", () => { const invalidStrategyId = "0x1234567890123456789012345678901234567890123456789012345678901234"; @@ -39,7 +39,7 @@ describe("Strategy Mapping", () => { }); describe("existsHandler", () => { - it("should return true for a valid strategy ID", () => { + it("returns true for a valid strategy ID", () => { const validStrategyId = "0x2f46bf157821dc41daa51479e94783bb0c8699eac63bf75ec450508ab03867ce"; @@ -48,7 +48,7 @@ describe("Strategy Mapping", () => { expect(exists).toBe(true); }); - it("should return true for a valid strategy ID in uppercase", () => { + it("returns true for a valid strategy ID in uppercase", () => { const validStrategyId = "0x2F46BF157821DC41DAA51479E94783BB0C8699EAC63BF75EC450508AB03867CE"; @@ -57,7 +57,7 @@ describe("Strategy Mapping", () => { expect(exists).toBe(true); }); - it("should return false for an invalid strategy ID", () => { + it("returns false for an invalid strategy ID", () => { const invalidStrategyId = "0x1234567890123456789012345678901234567890123456789012345678901234"; diff --git a/packages/processors/test/strategy/strategyHandler.factory.spec.ts b/packages/processors/test/strategy/strategyHandler.factory.spec.ts index 6f77033..bdfd641 100644 --- a/packages/processors/test/strategy/strategyHandler.factory.spec.ts +++ b/packages/processors/test/strategy/strategyHandler.factory.spec.ts @@ -12,7 +12,7 @@ import { import { ChainId, ILogger } from "@grants-stack-indexer/shared"; import { ProcessorDependencies, StrategyHandlerFactory } from "../../src/internal.js"; -import { DVMDDirectTransferStrategyHandler } from "../../src/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.js"; +import { DVMDDirectTransferStrategyHandler } from "../../src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.js"; describe("StrategyHandlerFactory", () => { const chainId = 10 as ChainId; diff --git a/packages/shared/src/types/events/registry.ts b/packages/shared/src/types/events/registry.ts index 5871ec9..6bcec46 100644 --- a/packages/shared/src/types/events/registry.ts +++ b/packages/shared/src/types/events/registry.ts @@ -5,7 +5,14 @@ import { Address, AnyEvent, Bytes32String, ContractName, ProcessorEvent } from " /** * This array is used to represent all Registry events. */ -const RegistryEventArray = ["ProfileCreated", "RoleGranted"] as const; +const RegistryEventArray = [ + "ProfileCreated", + "ProfileMetadataUpdated", + "ProfileNameUpdated", + "ProfileOwnerUpdated", + "RoleGranted", + "RoleRevoked", +] as const; /** * This type is used to represent a Registry events. @@ -19,7 +26,15 @@ export type RegistryEventParams = T extends "ProfileCre ? ProfileCreatedParams : T extends "RoleGranted" ? RoleGrantedParams - : never; + : T extends "ProfileMetadataUpdated" + ? ProfileMetadataUpdatedParams + : T extends "ProfileNameUpdated" + ? ProfileNameUpdatedParams + : T extends "ProfileOwnerUpdated" + ? ProfileOwnerUpdatedParams + : T extends "RoleRevoked" + ? RoleRevokedParams + : never; // ============================================================================= // =============================== Event Parameters ============================ @@ -32,12 +47,32 @@ export type ProfileCreatedParams = { owner: Address; anchor: Address; }; +export type ProfileMetadataUpdatedParams = { + profileId: Bytes32String; + metadata: [protocol: bigint, pointer: string]; +}; +export type ProfileNameUpdatedParams = { + profileId: Bytes32String; + name: string; + anchor: Address; +}; +export type ProfileOwnerUpdatedParams = { + profileId: Bytes32String; + owner: Address; +}; + export type RoleGrantedParams = { role: Bytes32String; account: Address; sender: Address; }; +export type RoleRevokedParams = { + role: Bytes32String; + account: Address; + sender: Address; +}; + /** * Type guard for Registry events. * @param event The event to check.