-
Notifications
You must be signed in to change notification settings - Fork 0
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
Conversation
} | ||
|
||
export class MetadataParsingFailed extends Error { | ||
constructor(additionalInfo?: string) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 🫡
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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", () => { |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import { calculateAmountInToken, calculateAmountInUsd } from "./tokenMath.js"; | |
import { calculateAmountInToken, calculateAmountInUsd } from "./index.js"; |
There was a problem hiding this comment.
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 ?)
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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
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); | ||
}); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exactly
packages/repository/src/external.ts
Outdated
@@ -35,17 +36,21 @@ export type { | |||
PartialApplication, | |||
} from "./types/application.types.js"; | |||
|
|||
export type { Donation, NewDonation } from "./types/donation.types.js"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export type { Donation, NewDonation } from "./types/donation.types.js"; | |
export type { Donation, NewDonation } from "./types/index.js"; |
packages/repository/src/external.ts
Outdated
@@ -35,17 +36,21 @@ export type { | |||
PartialApplication, | |||
} from "./types/application.types.js"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} from "./types/application.types.js"; | |
} from "./types/index.js"; |
timestamp: Date; | ||
}; | ||
|
||
export type NewDonation = Donation; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets gooo
🤖 Linear
Closes GIT-140 GIT-142
Description
Allocated
event handler for DVMD Direct Transfer strategyAllocatedWithX
events from EnvioDonationRepository
Checklist before requesting a review