Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: all event handlers for allo contract #39

Merged
merged 3 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -29,12 +29,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 @@ -61,12 +61,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 @@ -200,11 +200,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 @@ -384,11 +384,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
Loading