generated from defi-wonderland/ts-turborepo-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# 🤖 Linear Closes GIT-63 ## Description - `Registered` and `Distributed` event handlers for Direct Voting Merkle Distribution Direct Transfer strategy - write an abstract class for Distributed since the logic is not attached to any strategy in particular, so it's reusable ## Checklist before requesting a review - [x] I have conducted a self-review of my code. - [x] I have conducted a QA. - [x] If it is a core feature, I have included comprehensive tests.
- Loading branch information
Showing
20 changed files
with
553 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
packages/processors/src/exceptions/projectNotFound.exception.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { ChainId } from "@grants-stack-indexer/shared"; | ||
|
||
export class ProjectNotFound extends Error { | ||
constructor(chainId: ChainId, anchorAddress: string) { | ||
super(`Project not found for chainId: ${chainId} and anchorAddress: ${anchorAddress}`); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
packages/processors/src/exceptions/roundNotFound.exception.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { ChainId } from "@grants-stack-indexer/shared"; | ||
|
||
export class RoundNotFound extends Error { | ||
constructor(chainId: ChainId, strategyAddress: string) { | ||
super(`Round not found for chainId: ${chainId} and strategyAddress: ${strategyAddress}`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
packages/processors/src/strategy/common/baseDistributed.handler.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { getAddress } from "viem"; | ||
|
||
import { Changeset } from "@grants-stack-indexer/repository"; | ||
import { ChainId, ProtocolEvent } from "@grants-stack-indexer/shared"; | ||
|
||
import { IEventHandler, ProcessorDependencies } from "../../internal.js"; | ||
|
||
type Dependencies = Pick<ProcessorDependencies, "roundRepository">; | ||
|
||
/** | ||
* BaseDistributedHandler: Processes 'Distributed' events | ||
* | ||
* - Handles distribution events across all strategies. | ||
* - Creates a changeset to increment the total distributed amount for a round. | ||
* - Serves as a base class as all strategies share the same logic for this event. | ||
* | ||
* @dev: | ||
* - Strategy handlers that want to handle the Distributed event should create an instance of this class corresponding to the event. | ||
* | ||
*/ | ||
|
||
export class BaseDistributedHandler implements IEventHandler<"Strategy", "Distributed"> { | ||
constructor( | ||
readonly event: ProtocolEvent<"Strategy", "Distributed">, | ||
private readonly chainId: ChainId, | ||
private readonly dependencies: Dependencies, | ||
) {} | ||
|
||
async handle(): Promise<Changeset[]> { | ||
const { roundRepository } = this.dependencies; | ||
const strategyAddress = getAddress(this.event.srcAddress); | ||
const round = await roundRepository.getRoundByStrategyAddress( | ||
this.chainId, | ||
strategyAddress, | ||
); | ||
|
||
if (!round) { | ||
//TODO: add logging that round was not found | ||
return []; | ||
} | ||
|
||
return [ | ||
{ | ||
type: "IncrementRoundTotalDistributed", | ||
args: { | ||
chainId: this.chainId, | ||
roundId: round.id, | ||
amount: BigInt(this.event.params.amount), | ||
}, | ||
}, | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./baseDistributed.handler.js"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 0 additions & 19 deletions
19
...c/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/distributed.handler.ts
This file was deleted.
Oops, something went wrong.
1 change: 0 additions & 1 deletion
1
.../processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
export * from "./distributed.handler.js"; | ||
export * from "./registered.handler.js"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
...processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/helpers/decoder.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { decodeAbiParameters, Hex } from "viem"; | ||
|
||
import { Address } from "@grants-stack-indexer/shared"; | ||
|
||
import { DVMDApplicationData } from "../types/index.js"; | ||
|
||
const DVMD_EVENT_DATA_DECODER = [ | ||
{ name: "data", type: "bytes" }, | ||
{ name: "recipientsCounter", type: "uint256" }, | ||
] as const; | ||
|
||
const DVMD_DATA_DECODER = [ | ||
{ name: "registryAnchor", type: "address" }, | ||
{ name: "recipientAddress", type: "address" }, | ||
{ | ||
name: "metadata", | ||
type: "tuple", | ||
components: [ | ||
{ name: "protocol", type: "uint256" }, | ||
{ name: "pointer", type: "string" }, | ||
], | ||
}, | ||
] as const; | ||
|
||
export const decodeDVMDApplicationData = (encodedData: Hex): DVMDApplicationData => { | ||
const values = decodeAbiParameters(DVMD_EVENT_DATA_DECODER, encodedData); | ||
|
||
const decodedData = decodeAbiParameters(DVMD_DATA_DECODER, values[0]); | ||
|
||
const results: DVMDApplicationData = { | ||
recipientsCounter: values[1].toString(), | ||
anchorAddress: decodedData[0] as Address, | ||
recipientAddress: decodedData[1] as Address, | ||
metadata: { | ||
protocol: Number(decodedData[2].protocol), | ||
pointer: decodedData[2].pointer, | ||
}, | ||
}; | ||
|
||
return results; | ||
}; |
11 changes: 11 additions & 0 deletions
11
...ges/processors/src/strategy/donationVotingMerkleDistributionDirectTransfer/types/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Address } from "@grants-stack-indexer/shared"; | ||
|
||
export type DVMDApplicationData = { | ||
recipientsCounter: string; | ||
anchorAddress: Address; | ||
recipientAddress: Address; | ||
metadata: { | ||
protocol: number; | ||
pointer: string; | ||
}; | ||
}; |
85 changes: 85 additions & 0 deletions
85
packages/processors/test/strategy/common/baseDistributed.handler.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { beforeEach, describe, expect, it, vi } from "vitest"; | ||
|
||
import { IRoundReadRepository, Round } from "@grants-stack-indexer/repository"; | ||
import { ChainId, ProtocolEvent } from "@grants-stack-indexer/shared"; | ||
|
||
import { BaseDistributedHandler } from "../../../src/strategy/common/baseDistributed.handler.js"; | ||
|
||
function createMockEvent( | ||
overrides: Partial<ProtocolEvent<"Strategy", "Distributed">> = {}, | ||
): ProtocolEvent<"Strategy", "Distributed"> { | ||
const defaultEvent: ProtocolEvent<"Strategy", "Distributed"> = { | ||
params: { | ||
amount: 1000, | ||
recipientAddress: "0x1234567890123456789012345678901234567890", | ||
recipientId: "0x1234567890123456789012345678901234567890", | ||
sender: "0x1234567890123456789012345678901234567890", | ||
}, | ||
eventName: "Distributed", | ||
srcAddress: "0x1234567890123456789012345678901234567890", | ||
blockNumber: 12345, | ||
blockTimestamp: 1000000000, | ||
chainId: 10 as ChainId, | ||
contractName: "Strategy", | ||
logIndex: 1, | ||
transactionFields: { | ||
hash: "0xd2352acdcd59e312370831ea927d51a1917654697a72434cd905a60897a5bb8b", | ||
transactionIndex: 6, | ||
from: "0xcBf407C33d68a55CB594Ffc8f4fD1416Bba39DA5", | ||
}, | ||
strategyId: "0x9fa6890423649187b1f0e8bf4265f0305ce99523c3d11aa36b35a54617bb0ec0", | ||
}; | ||
|
||
return { ...defaultEvent, ...overrides }; | ||
} | ||
|
||
describe("BaseDistributedHandler", () => { | ||
let handler: BaseDistributedHandler; | ||
let mockRoundRepository: IRoundReadRepository; | ||
let mockEvent: ProtocolEvent<"Strategy", "Distributed">; | ||
const chainId = 10 as ChainId; | ||
|
||
beforeEach(() => { | ||
mockRoundRepository = { | ||
getRoundByStrategyAddress: vi.fn(), | ||
} as unknown as IRoundReadRepository; | ||
}); | ||
|
||
it("increment round total distributed when round is found", async () => { | ||
mockEvent = createMockEvent(); | ||
const mockRound = { id: "round1" } as Round; | ||
|
||
vi.spyOn(mockRoundRepository, "getRoundByStrategyAddress").mockResolvedValue(mockRound); | ||
|
||
handler = new BaseDistributedHandler(mockEvent, chainId, { | ||
roundRepository: mockRoundRepository, | ||
}); | ||
|
||
const result = await handler.handle(); | ||
|
||
expect(result).toEqual([ | ||
{ | ||
type: "IncrementRoundTotalDistributed", | ||
args: { | ||
chainId, | ||
roundId: "round1", | ||
amount: BigInt(mockEvent.params.amount), | ||
}, | ||
}, | ||
]); | ||
}); | ||
|
||
it("returns an empty array when round is not found", async () => { | ||
mockEvent = createMockEvent(); | ||
|
||
vi.spyOn(mockRoundRepository, "getRoundByStrategyAddress").mockResolvedValue(undefined); | ||
|
||
handler = new BaseDistributedHandler(mockEvent, chainId, { | ||
roundRepository: mockRoundRepository, | ||
}); | ||
|
||
const result = await handler.handle(); | ||
|
||
expect(result).toEqual([]); | ||
}); | ||
}); |
Oops, something went wrong.