Skip to content

Commit

Permalink
feat: all event handlers for allo contract (#39)
Browse files Browse the repository at this point in the history
# 🤖 Linear

Closes GIT-137 GIT-149 GIT-150 GIT-151 GIT-152

## Description

Added all the remaining handlers for Allo contract events.

## Checklist before requesting a review

-   [ ] I have conducted a self-review of my code.
-   [ ] I have conducted a QA.
-   [ ] If it is a core feature, I have included comprehensive tests.
  • Loading branch information
0xkenj1 authored Dec 10, 2024
1 parent 8d06292 commit 1d83d5d
Show file tree
Hide file tree
Showing 24 changed files with 1,231 additions and 132 deletions.
6 changes: 5 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ module.exports = {
"@typescript-eslint/no-unsafe-return": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{ argsIgnorePattern: "_+", ignoreRestSiblings: true },
{
argsIgnorePattern: "_+",
ignoreRestSiblings: true,
destructuredArrayIgnorePattern: "^_",
},
],
"@typescript-eslint/prefer-as-const": "warn",
},
Expand Down
12 changes: 6 additions & 6 deletions packages/data-flow/test/unit/eventsRegistry.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ describe("InMemoryEventsRegistry", () => {
srcAddress: "0x123",
strategyId: "0xstrategy",
params: {
poolId: 1n,
poolId: "1",
profileId: "0x456",
strategy: "0x789",
token: "0xtoken",
amount: 0n,
metadata: [1n, "0xmetadata"],
amount: "0",
metadata: ["1", "0xmetadata"],
},
transactionFields: {
hash: "0xabc",
Expand All @@ -62,12 +62,12 @@ describe("InMemoryEventsRegistry", () => {
srcAddress: "0x123",
strategyId: "0xstrategy",
params: {
poolId: 1n,
poolId: "1",
profileId: "0x456",
strategy: "0x789",
token: "0xtoken",
amount: 0n,
metadata: [1n, "0xmetadata"],
amount: "0",
metadata: ["1", "0xmetadata"],
},
transactionFields: {
hash: "0xabc",
Expand Down
12 changes: 6 additions & 6 deletions packages/data-flow/test/unit/orchestrator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,11 @@ describe("Orchestrator", { sequential: true }, () => {
"0x6f9291df02b2664139cec5703c124e4ebce32879c74b6297faa1468aa5ff9ebf" as Hex;
const mockEvent = createMockEvent("Allo", "PoolCreated", 1, {
strategy: strategyAddress,
poolId: 1n,
poolId: "1",
profileId: "0x123",
token: "0x123",
amount: 100n,
metadata: [1n, "1"],
amount: "100",
metadata: ["1", "1"],
});

const eventsProcessorSpy = vi.spyOn(orchestrator["eventsProcessor"], "processEvent");
Expand Down Expand Up @@ -396,11 +396,11 @@ describe("Orchestrator", { sequential: true }, () => {
"0x6f9291df02b2664139cec5703c124e4ebce32879c74b6297faa1468aa5ff9ebf" as Hex;
const poolCreatedEvent = createMockEvent("Allo", "PoolCreated", 1, {
strategy: strategyAddress,
poolId: 1n,
poolId: "1",
profileId: "0x123",
token: "0x123",
amount: 100n,
metadata: [1n, "1"],
amount: "100",
metadata: ["1", "1"],
});
const registeredEvent = createMockEvent(
"Strategy",
Expand Down
38 changes: 36 additions & 2 deletions packages/processors/src/processors/allo/allo.processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { AlloEvent, ChainId, ProcessorEvent } from "@grants-stack-indexer/shared

import type { IProcessor, ProcessorDependencies } from "../../internal.js";
import { UnsupportedEventException } from "../../internal.js";
import { PoolCreatedHandler } from "./handlers/index.js";
import {
PoolCreatedHandler,
PoolFundedHandler,
PoolMetadataUpdatedHandler,
RoleGrantedHandler,
RoleRevokedHandler,
} from "./handlers/index.js";

/**
* AlloProcessor handles the processing of Allo V2 events from the Allo contract by delegating them to the appropriate handler
Expand All @@ -17,7 +23,35 @@ export class AlloProcessor implements IProcessor<"Allo", AlloEvent> {
async process(event: ProcessorEvent<"Allo", AlloEvent>): Promise<Changeset[]> {
switch (event.eventName) {
case "PoolCreated":
return new PoolCreatedHandler(event, this.chainId, this.dependencies).handle();
return new PoolCreatedHandler(
event as ProcessorEvent<"Allo", "PoolCreated">,
this.chainId,
this.dependencies,
).handle();
case "PoolFunded":
return new PoolFundedHandler(
event as ProcessorEvent<"Allo", "PoolFunded">,
this.chainId,
this.dependencies,
).handle();
case "RoleGranted":
return new RoleGrantedHandler(
event as ProcessorEvent<"Allo", "RoleGranted">,
this.chainId,
this.dependencies,
).handle();
case "PoolMetadataUpdated":
return new PoolMetadataUpdatedHandler(
event as ProcessorEvent<"Allo", "PoolMetadataUpdated">,
this.chainId,
this.dependencies,
).handle();
case "RoleRevoked":
return new RoleRevokedHandler(
event as ProcessorEvent<"Allo", "RoleRevoked">,
this.chainId,
this.dependencies,
).handle();
default:
throw new UnsupportedEventException("Allo", event.eventName);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/processors/src/processors/allo/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export * from "./poolCreated.handler.js";
export * from "./poolFunded.handler.js";
export * from "./poolMetadataUpdated.handler.js";
export * from "./roleGranted.handler.js";
export * from "./roleRevoked.handler.js";
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ export class PoolCreatedHandler implements IEventHandler<"Allo", "PoolCreated">
poolId,
token: tokenAddress,
strategy: strategyAddress,
amount: fundedAmount,
amount,
} = this.event.params;
const fundedAmount = BigInt(amount);
const { hash: txHash, from: txFrom } = this.event.transactionFields;
const strategyId = this.event.strategyId;

Expand Down Expand Up @@ -99,7 +100,7 @@ export class PoolCreatedHandler implements IEventHandler<"Allo", "PoolCreated">
// transaction sender
const createdBy = txFrom ?? (await evmProvider.getTransaction(txHash)).from;

const roundRoles = getRoundRoles(poolId);
const roundRoles = getRoundRoles(BigInt(poolId));

const newRound: NewRound = {
chainId: this.chainId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { Changeset } from "@grants-stack-indexer/repository";
import type { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared";
import { getToken, UnknownToken } from "@grants-stack-indexer/shared";

import type { IEventHandler, ProcessorDependencies } from "../../../internal.js";
import { getTokenAmountInUsd } from "../../../helpers/index.js";

type Dependencies = Pick<ProcessorDependencies, "roundRepository" | "logger" | "pricingProvider">;

/**
* Handles the PoolFunded event for the Allo protocol.
*
* This handler performs the following core actions when a pool is funded:
* - Fetches the round metadata from the metadata provider.
* - Returns the changeset to update the round with the new metadata.
*/
export class PoolFundedHandler implements IEventHandler<"Allo", "PoolFunded"> {
constructor(
readonly event: ProcessorEvent<"Allo", "PoolFunded">,
private readonly chainId: ChainId,
private readonly dependencies: Dependencies,
) {}
/* @inheritdoc */
async handle(): Promise<Changeset[]> {
const poolId = this.event.params.poolId.toString();
const fundedAmount = BigInt(this.event.params.amount);
const { roundRepository, pricingProvider } = this.dependencies;

const round = await roundRepository.getRoundByIdOrThrow(this.chainId, poolId);

const token = getToken(this.chainId, round.matchTokenAddress);

//TODO: Review this on Advace Recovery Milestone
if (!token) throw new UnknownToken(round.matchTokenAddress, this.chainId);

const { amountInUsd } = await getTokenAmountInUsd(
pricingProvider,
token,
fundedAmount,
this.event.blockTimestamp,
);

return [
{
type: "IncrementRoundFundedAmount",
args: {
chainId: this.chainId,
roundId: round.id,
fundedAmount,
fundedAmountInUsd: amountInUsd,
},
},
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { parseUnits } from "viem";

import type { Changeset } from "@grants-stack-indexer/repository";
import type { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared";
import { getToken } from "@grants-stack-indexer/shared";

import type { IEventHandler, ProcessorDependencies } from "../../../internal.js";
import { getTokenAmountInUsd } from "../../../helpers/index.js";
import { RoundMetadataSchema } from "../../../schemas/index.js";

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

/**
* Handles the PoolMetadataUpdated event for the Allo protocol.
*
* This handler performs the following core actions when a pool metadata is updated:
* - Fetches the round metadata from the metadata provider.
* - Returns the changeset to update the round with the new metadata.
*/
export class PoolMetadataUpdatedHandler implements IEventHandler<"Allo", "PoolMetadataUpdated"> {
constructor(
readonly event: ProcessorEvent<"Allo", "PoolMetadataUpdated">,
private readonly chainId: ChainId,
private readonly dependencies: Dependencies,
) {}
/* @inheritdoc */
async handle(): Promise<Changeset[]> {
const [_protocol, metadataPointer] = this.event.params.metadata;
const { metadataProvider, pricingProvider, roundRepository } = this.dependencies;

const metadata = await metadataProvider.getMetadata<{
round?: unknown;
application?: unknown;
}>(metadataPointer);

const round = await roundRepository.getRoundByIdOrThrow(
this.chainId,
this.event.params.poolId.toString(),
);

let matchAmount = round.matchAmount;
let matchAmountInUsd = round.matchAmountInUsd;

const parsedRoundMetadata = RoundMetadataSchema.safeParse(metadata?.round);
const token = getToken(this.chainId, round.matchTokenAddress);

if (parsedRoundMetadata.success && token) {
matchAmount = parseUnits(
parsedRoundMetadata.data.quadraticFundingConfig.matchingFundsAvailable.toString(),
token.decimals,
);
matchAmountInUsd = (
await getTokenAmountInUsd(
pricingProvider,
token,
matchAmount,
this.event.blockTimestamp,
)
).amountInUsd;
}

return [
{
type: "UpdateRound",
args: {
chainId: this.chainId,
roundId: this.event.params.poolId.toString(),
round: {
matchAmount,
matchAmountInUsd,
applicationMetadataCid: metadataPointer,
applicationMetadata: metadata?.application ?? {},
roundMetadataCid: metadataPointer,
roundMetadata: metadata?.round ?? {},
},
},
},
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { getAddress } from "viem";

import type { Changeset, Round } from "@grants-stack-indexer/repository";
import type { ChainId, ProcessorEvent } from "@grants-stack-indexer/shared";

import type { IEventHandler, ProcessorDependencies } from "../../../internal.js";

type Dependencies = Pick<ProcessorDependencies, "roundRepository">;

/**
* Handles the RoleGranted event for the Allo protocol.
*
* This handler performs the following core actions when a new role is granted:
* - Insert a new round role if the role granted is admin or manager.
* - Insert a new pending round role if the role granted is not admin or manager.
* - Return the changeset.
*/
export class RoleGrantedHandler implements IEventHandler<"Allo", "RoleGranted"> {
constructor(
readonly event: ProcessorEvent<"Allo", "RoleGranted">,
private readonly chainId: ChainId,
private readonly dependencies: Dependencies,
) {}
/* @inheritdoc */
async handle(): Promise<Changeset[]> {
const role = this.event.params.role.toLowerCase();
const account = getAddress(this.event.params.account);
const { roundRepository } = this.dependencies;

let round: Round | undefined = undefined;

// search for a round where the admin role is the role granted
round = await roundRepository.getRoundByRole(this.chainId, "admin", role);
if (round) {
return [
{
type: "InsertRoundRole",
args: {
roundRole: {
chainId: this.chainId,
roundId: round.id,
role: "admin",
address: account,
createdAtBlock: BigInt(this.event.blockNumber),
},
},
},
];
}

// search for a round where the manager role is the role granted
round = await roundRepository.getRoundByRole(this.chainId, "manager", role);
if (round) {
return [
{
type: "InsertRoundRole",
args: {
roundRole: {
chainId: this.chainId,
roundId: round.id,
role: "manager",
address: account,
createdAtBlock: BigInt(this.event.blockNumber),
},
},
},
];
}

return [
{
type: "InsertPendingRoundRole",
args: {
pendingRoundRole: {
chainId: this.chainId,
role: role,
address: account,
createdAtBlock: BigInt(this.event.blockNumber),
},
},
},
];
}
}
Loading

0 comments on commit 1d83d5d

Please sign in to comment.