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: base strategy processor & dvmd strategy factory #16

Merged
merged 7 commits into from
Oct 28, 2024

Conversation

0xnigir1
Copy link
Collaborator

@0xnigir1 0xnigir1 commented Oct 24, 2024

🤖 Linear

Closes GIT-60 GIT-61 GIT-62

Description

  • StrategyHandlerFactory to create the proper Strategy handler based on strategyId
  • BaseStrategyHandler abstract class w/ default implementation for fetch functions (some strategies require custom logic)
  • DVMDDirectTransferStrategy handler
  • Distributed and Registered handlers for DVMD strategy (PR Feat/dvmd dt event handlers #17)
  • refactored TODOs from PoolCreatedHandler

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.

Copy link

linear bot commented Oct 24, 2024

const _strategyId = strategyId.toLowerCase();

switch (_strategyId) {
case "0x6f9291df02b2664139cec5703c124e4ebce32879c74b6297faa1468aa5ff9ebf":
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe worth extracting these contract addresses out into a map for readability

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds nice

# 🤖 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.
@0xnigir1 0xnigir1 marked this pull request as ready for review October 25, 2024 20:58
@0xnigir1 0xnigir1 requested a review from jahabeebs October 25, 2024 21:02
Copy link
Collaborator

@jahabeebs jahabeebs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some suggestions 👀

strategyId,
);

// const strategy = extractStrategyFromId(strategyId);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leftover comment?

token.decimals,
);
let matchAmount = {
matchAmount: 0n,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm maybe worth naming the internal matchAmount something like matchAmountBigInt or maybe the outer matchAmount could be matchAmountObj?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like that

this.name = name;
}

async fetchStrategyTimings(_strategyAddress: Address): Promise<StrategyTimings> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe an /** @inheritdoc */ for these functions?

"roundRepository" | "projectRepository" | "metadataProvider"
>;

export class DVMDRegisteredHandler implements IEventHandler<"Strategy", "Registered"> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worth having docs for the class + inherit docs for the functions?

strategyAddress,
);

if (!round) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed in the other handler where you have (!round) it doesn't throw an exception--should only this one throw an exception?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the expected flow but it's a nice catch, will write it down and have it as Q for Gitcoin

},
] as const;

export const decodeDVMDApplicationData = (encodedData: Hex): DVMDApplicationData => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worth it to have docs here?

import type { StrategyHandlerConstructor } from "../internal.js";
import { DVMDDirectTransferStrategyHandler } from "./donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.js";

const strategyIdToHandler: Readonly<Record<string, StrategyHandlerConstructor>> = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good as a map now 🗺️

const _strategyId = strategyId.toLowerCase() as Hex;
const StrategyHandlerClass = getHandler(_strategyId);

console.log("StrategyHandlerClass", StrategyHandlerClass);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you mean to log this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no jajaja

@0xnigir1 0xnigir1 requested a review from jahabeebs October 28, 2024 13:10
jahabeebs
jahabeebs previously approved these changes Oct 28, 2024
Copy link
Collaborator

@jahabeebs jahabeebs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

@0xkenj1 0xkenj1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments, but great job ser !! 🫡


export class UnsupportedStrategy extends Error {
constructor(strategyId: Hex) {
super(`Strategy ${strategyId} unsupported`);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add some more context here, like the address ? Maybe this is correct and we should enrich the log once is bubbled up. wdyt?

Copy link
Collaborator Author

@0xnigir1 0xnigir1 Oct 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmm we can take EBO's error handling approach and a context object for errors. i think that with bubbling the event should be enough almost every time right? is the most generic context object

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤝

export * from "./strategy/index.js";

// Strategy
export * from "./strategy/common/index.js";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can colapse all of these using strategy/index.js

Comment on lines +32 to +34
_matchingFundsAvailable: number,
_token: Token,
_blockTimestamp: number,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason why using underscores here ? i don't remember if we had a best practice for this or sth

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

underscore in function args means "unused variables"

);

if (!round) {
//TODO: add logging that round was not found
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets add a console.log here to make it easier to replace it by the logger after :)

Comment on lines 14 to 15
import { calculateAmountInUsd } from "../../helpers/tokenMath.js";
import { getDateFromTimestamp } from "../../helpers/utils.js";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imports from index , lets avoid using specific paths

import type { StrategyHandlerConstructor } from "../internal.js";
import { DVMDDirectTransferStrategyHandler } from "./donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.js";

const strategyIdToHandler: Readonly<Record<string, StrategyHandlerConstructor>> = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe is worth to add some comment or doc here

const _strategyId = strategyId.toLowerCase() as Hex;
const StrategyHandlerClass = getHandler(_strategyId);

return StrategyHandlerClass ? new StrategyHandlerClass(chainId, dependencies) : undefined;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we throw an error here and do a try catch wherever we need it ?

Copy link
Collaborator Author

@0xnigir1 0xnigir1 Oct 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think is not strictly necessary, if caller's action is to throw, let the caller throw. else in everyplace where code flows goes on even if strategy is undefined, we would need the try/catch which is more costly in computer terms than just asking if it's undefined

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤝

Comment on lines +26 to +63
describe("fetchStrategyTimings", () => {
it("returns default timings", async () => {
const address: Address = "0x1234567890123456789012345678901234567890";
const timings = await handler.fetchStrategyTimings(address);

expect(timings).toEqual({
applicationsStartTime: null,
applicationsEndTime: null,
donationsStartTime: null,
donationsEndTime: null,
});
});
});

describe("fetchMatchAmount", () => {
it("returns default match amount", async () => {
const matchingFundsAvailable = 1000;
const token: Token = {
address: "0x1234567890123456789012345678901234567890",
decimals: 18,
code: "ETH" as TokenCode,
priceSourceCode: "ETH" as TokenCode,
};
const blockTimestamp = 1625097600; // Example timestamp

const result = await handler.fetchMatchAmount(
matchingFundsAvailable,
token,
blockTimestamp,
);

expect(result).toEqual({
matchAmount: 0n,
matchAmountInUsd: "0",
});
});
});
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is worth to test faulty scenarios here ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like what scenario?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i imagined invalid address for example, but reading the code again, i think it doesn't make sience since its is the base class

return { ...defaultEvent, ...overrides };
}

describe("BaseDistributedHandler", () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, faulty scenarios

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like what scenario?

});
expect(BaseDistributedHandler.prototype.handle).toHaveBeenCalled();
});

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, faulty scenarios, what happened if event is not supported ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

event not supported is tested, is the last test of the suite

@0xnigir1 0xnigir1 merged commit 9ad1569 into dev Oct 28, 2024
6 checks passed
@0xnigir1 0xnigir1 deleted the feat/base-strategy-processors branch October 28, 2024 22:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants