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: dvmd direct transfer allocated handler #29

Merged
merged 4 commits into from
Nov 12, 2024

Conversation

0xnigir1
Copy link
Collaborator

@0xnigir1 0xnigir1 commented Nov 8, 2024

🤖 Linear

Closes GIT-140 GIT-142

Description

  • Allocated event handler for DVMD Direct Transfer strategy
  • add AllocatedWithX events from Envio
  • adds DonationRepository

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 Nov 8, 2024

}

export class MetadataParsingFailed extends Error {
constructor(additionalInfo?: string) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

should move these two errors to exceptions?

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 thought maybe they're only specific to this handler, but if later i need it for another Handler, i can refactor and move to exceptions, wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

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

i agree with jahabeebs, lets keep them on its specific directory to avoid noise on this file... we can have exceptions/handlers/DVMD.... or some similar directory structure, wdyt ?

import { calculateAmountInToken, calculateAmountInUsd } from "./tokenMath.js";

// sometimes coingecko returns no prices for 1 hour range, 2 hours works better
const TIMESTAMP_DELTA_RANGE = 2 * 60 * 60 * 1000;
Copy link
Collaborator

Choose a reason for hiding this comment

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

do you think this might be better as an env variable to avoid a code change if their api behavior changes?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

there isn't a specific api behaviour here actually, this comment is smth Gitcoin team found out experimenting,
i think for now is not needed an env variable but now im thinking if maybe this can be the default value on Coingecko provider instead of API caller passing timestamp.now() + DELTA_RANGE everytime. i leave it for reviewing later 🫡

Copy link
Collaborator

Choose a reason for hiding this comment

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

agree with you nigiri, lets have this value as default ( within the CoingeckoProvider) and make the param optional , wdyt ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

will add a task in linear to refactor in another PR

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

const tokenPriceInUsdBN = new BigNumber(tokenPriceInUsd);
const scaleFactor = new BigNumber(10).pow(tokenDecimals);

return BigInt(amountInUsdBN.multipliedBy(scaleFactor).dividedBy(tokenPriceInUsdBN).toFixed(0));
Copy link
Collaborator

Choose a reason for hiding this comment

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

might need some protection against division by zero (and possibly invalid/NaN values, not sure all the responses coingecko can return)

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 was relying on the exception that bignumber.js throws for ZeroDivision, i'll clarify in natssec that it throws an exception in that case)

expect(calculateAmountInToken("2", "1000000000000000000", 18)).toBe(2n);
});

it("throw an error for zero token price", () => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this might be useful as a custom exception given that it's a very specific case (which we can then add to the unit test case)

Copy link
Collaborator

Choose a reason for hiding this comment

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

another test case to consider would be if you get expected results when you vary the decimal precision (unless the api always returns the same precision)

import { calculateAmountInToken, calculateAmountInUsd } from "./tokenMath.js";

// sometimes coingecko returns no prices for 1 hour range, 2 hours works better
const TIMESTAMP_DELTA_RANGE = 2 * 60 * 60 * 1000;
Copy link
Collaborator

Choose a reason for hiding this comment

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

agree with you nigiri, lets have this value as default ( within the CoingeckoProvider) and make the param optional , wdyt ?

import { Token } from "@grants-stack-indexer/shared";

import { TokenPriceNotFoundError } from "../internal.js";
import { calculateAmountInToken, calculateAmountInUsd } from "./tokenMath.js";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
import { calculateAmountInToken, calculateAmountInUsd } from "./tokenMath.js";
import { calculateAmountInToken, calculateAmountInUsd } from "./index.js";

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

how to make autoimport work magically with this? maybe it's easier to have one single file called index.js with all the code ?)

Copy link
Collaborator

Choose a reason for hiding this comment

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

i know that is annoying but, it save us some future headaches 🤣

const tokenPrice = await pricingProvider.getTokenPrice(
token.priceSourceCode,
timestamp,
timestamp + TIMESTAMP_DELTA_RANGE,
Copy link
Collaborator

Choose a reason for hiding this comment

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

in addition to prev comment, instead timestamp + TIMESTAMP_DELTA_RANGE as param , just delta

const closestPrice = await pricingProvider.getTokenPrice(
token.priceSourceCode,
timestamp,
timestamp + TIMESTAMP_DELTA_RANGE,
Copy link
Collaborator

Choose a reason for hiding this comment

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

ditto

*/
export const calculateAmountInToken = (
amountInUSD: string,
tokenPriceInUsd: string | number,
Copy link
Collaborator

Choose a reason for hiding this comment

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

should this always be string ?

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 left it open because pricing provider returns number because coingecko returns a number (anyways, it doesn't affect the purpose of the function)

Copy link
Collaborator

Choose a reason for hiding this comment

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

oh, got it , now i remember

Comment on lines 192 to 204
it("throws OriginMissing if origin is undefined", async () => {
mockEvent = createMockEvent();
//forcefully remove origin from mockEvent
mockEvent.params.origin = undefined as unknown as `0x${string}`;

handler = new DVMDAllocatedHandler(mockEvent, chainId, {
roundRepository: mockRoundRepository,
applicationRepository: mockApplicationRepository,
pricingProvider: mockPricingProvider,
});

await expect(handler.handle()).rejects.toThrow(OriginMissing);
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

same comment as above

);

if (!round) {
throw new RoundNotFound(this.chainId, normalizedStrategyAddress);
Copy link
Collaborator

Choose a reason for hiding this comment

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

this is out of scope, but in this case this should be a critical error, right? i mean the round should always be defined for the strategy

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

exactly

@@ -35,17 +36,21 @@ export type {
PartialApplication,
} from "./types/application.types.js";

export type { Donation, NewDonation } from "./types/donation.types.js";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
export type { Donation, NewDonation } from "./types/donation.types.js";
export type { Donation, NewDonation } from "./types/index.js";

@@ -35,17 +36,21 @@ export type {
PartialApplication,
} from "./types/application.types.js";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
} from "./types/application.types.js";
} from "./types/index.js";

timestamp: Date;
};

export type NewDonation = Donation;
Copy link
Collaborator

Choose a reason for hiding this comment

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

why do we need this, i would rather keep just Donation

Copy link
Collaborator Author

@0xnigir1 0xnigir1 Nov 11, 2024

Choose a reason for hiding this comment

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

i think is better and cleaner to have separate typing (or interfaces/classes) for the "select" type, the "insert" typing "update" typing, even if they exactly match

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.

lets gooo

@0xnigir1 0xnigir1 merged commit 658bd7b into dev Nov 12, 2024
6 checks passed
@0xnigir1 0xnigir1 deleted the feat/dvmd-dt-allocated-handler branch November 12, 2024 20:18
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