Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR migrates award and incentive program financial fields from numeric ChangesType System Migration from EnsTokens to Price
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR migrates award/incentive-program and referral-program currency handling away from the local EnsTokens number type to @ensnode/ensnode-sdk’s Price model, centralizing “smallest-unit → display value” conversion in a shared helper.
Changes:
- Replace
EnsTokensusage withPriceand useparseEnsTokens(...)where financial amounts are authored in data files. - Introduce
interpretCurrency(Price) -> numberindata/shared/currencies.tsand update UI to use it (replacingparseReferralProgramCurrency). - Update award/incentive-program utilities to operate on the new
Pricetype.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| ensawards.org/src/utils/referralProgram.ts | Removes the old parseReferralProgramCurrency helper from this module. |
| ensawards.org/src/components/molecules/ReferralProgramEditionInfo.tsx | Uses interpretCurrency for award-pool remaining display. |
| ensawards.org/src/components/atoms/cards/referrerCard/rev-share/index.tsx | Replaces currency parsing with interpretCurrency across rev-share UI fields. |
| ensawards.org/src/components/atoms/cards/referrerCard/pie-split/index.tsx | Uses interpretCurrency for pie-split award value display. |
| ensawards.org/src/components/atoms/cards/referralProgramEditionCard/shared.tsx | Uses interpretCurrency for award-pool display in shared card components. |
| ensawards.org/src/components/atoms/cards/referralProgramEditionCard/rev-share/hero.tsx | Switches rev-share hero min-threshold display to interpretCurrency. |
| ensawards.org/src/components/atoms/cards/contractNamingSeasonAwardCard/index.tsx | Updates contract-naming award card to format/display Price values via interpretCurrency. |
| ensawards.org/data/shared/ensTokens.ts | Removes the local EnsTokens type export (keeps formatters + conversion constant). |
| ensawards.org/data/shared/currencies.ts | Adds interpretCurrency helper backed by getCurrencyInfo. |
| ensawards.org/data/incentive-programs/utils.ts | Updates remaining-pool and sum calculations to work with Price via interpretCurrency. |
| ensawards.org/data/incentive-programs/types.ts | Changes totalAwardPool type from EnsTokens to Price. |
| ensawards.org/data/incentive-programs/ens-contract-naming-season/index.ts | Migrates authored award pool amount to parseEnsTokens. |
| ensawards.org/data/incentive-programs/ens-contract-naming-season/awards.ts | Migrates authored award price values to parseEnsTokens. |
| ensawards.org/data/awards/utils.ts | Updates sorting/validation helpers to accept Price and convert via interpretCurrency. |
| ensawards.org/data/awards/utils.test.ts | Updates tests to construct award prices using parseEnsTokens. |
| ensawards.org/data/awards/types.ts | Updates AwardFinancial.price type from EnsTokens to Price. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
ensawards.org/src/components/atoms/cards/referrerCard/rev-share/index.tsx (1)
136-146:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winMissing negative-value guard for
additionalRevenueRequiredInUSD.The
userFacingAdditionalRevenueRequiredguard at line 145 only maps"$0.00"→"$0.01"but doesn't clamp negative amounts. If a data inconsistency causesreferrer.totalBaseRevenueContribution.amount > editionRules.minBaseRevenueContribution.amountwhile!referrer.isQualified, the tooltip renders"must achieve at least an additional US -$50.00".Additionally, the inline
Price-shaped object mixes.amountfrom two differentPriceinstances while taking.currencyonly fromminBaseRevenueContribution. If the two prices ever have different currencies, the arithmetic is silently incorrect.🛡️ Proposed fix
-const additionalRevenueRequiredInUSD = usdFormatter.format( - interpretCurrency({ - currency: editionRules.minBaseRevenueContribution.currency, - amount: - editionRules.minBaseRevenueContribution.amount - - referrer.totalBaseRevenueContribution.amount, - }), -); - -const userFacingAdditionalRevenueRequired = - additionalRevenueRequiredInUSD === "$0.00" ? "$0.01" : additionalRevenueRequiredInUSD; +const additionalRevenueRequired = Math.max( + 0, + interpretCurrency(editionRules.minBaseRevenueContribution) - + interpretCurrency(referrer.totalBaseRevenueContribution), +); +const additionalRevenueRequiredInUSD = usdFormatter.format(additionalRevenueRequired); +const userFacingAdditionalRevenueRequired = + additionalRevenueRequiredInUSD === "$0.00" ? "$0.01" : additionalRevenueRequiredInUSD;This also removes the fragile inline
Priceobject construction that directly couples to internal SDK fields.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ensawards.org/src/components/atoms/cards/referrerCard/rev-share/index.tsx` around lines 136 - 146, The guard for additionalRevenueRequiredInUSD is incomplete and you also construct a fragile inline Price by mixing fields from editionRules.minBaseRevenueContribution and referrer.totalBaseRevenueContribution; update the calculation so you first compute a numeric delta only when both prices share the same currency (compare editionRules.minBaseRevenueContribution.currency with referrer.totalBaseRevenueContribution.currency) and clamp negative deltas to zero, then pass that non-negative numeric amount and the correct currency into interpretCurrency/usdFormatter to produce additionalRevenueRequiredInUSD; finally, set userFacingAdditionalRevenueRequired to "$0.01" when the formatted USD equals "$0.00" (after clamping) so the tooltip never shows negative values or mixes currencies.ensawards.org/data/incentive-programs/utils.ts (1)
29-36: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winConsider using an explicit type predicate for version-agnostic type narrowing.
The
.filter()at line 31 relies on TypeScript 5.5+ discriminated-union auto-narrowing to safely accessaward.priceon line 34. While this works with modern TypeScript, an explicit type predicate would harden the code against older versions and improve clarity:Recommended alternative with explicit type predicate
import { type Award, AwardTypes } from "data/awards/types"; import { INCENTIVE_PROGRAMS } from "data/incentive-programs"; import type { IncentiveProgram, IncentiveProgramSlug } from "data/incentive-programs/types"; import { interpretCurrency } from "data/shared/currencies"; + +const isFinancialAward = (award: Award): award is AwardFinancial => + award.type === AwardTypes.FinancialAward; const incentiveProgramFinancialAwards = getAwardsByIncentiveProgramSlug( incentiveProgramSlug, -).filter((award) => award.type === AwardTypes.FinancialAward); +).filter(isFinancialAward);Also add
AwardFinancialto the import fromdata/awards/types.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ensawards.org/data/incentive-programs/utils.ts` around lines 29 - 36, Replace the implicit narrowing in the filter with an explicit type predicate so the result is statically recognized as financial awards: import AwardFinancial from data/awards/types (add AwardFinancial to the existing import) and change the filter callback on getAwardsByIncentiveProgramSlug(incentiveProgramSlug) to use a predicate signature (e.g., (award): award is AwardFinancial => award.type === AwardTypes.FinancialAward) so that interpretCurrency(award.price) is safe regardless of TypeScript version.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ensawards.org/data/awards/utils.test.ts`:
- Around line 5-8: Add tests for isValidAwardValue by constructing Price values
via parseEnsTokens and asserting expected booleans: call
isValidAwardValue(parseEnsTokens("0")) -> false,
isValidAwardValue(parseEnsTokens("-1")) -> false, and
isValidAwardValue(parseEnsTokens("1")) (or another positive amount) -> true;
place these assertions alongside existing tests for sortFinancialAwardsByPrice
and import/use parseEnsTokens and isValidAwardValue to exercise the updated
signature.
In `@ensawards.org/data/shared/currencies.ts`:
- Around line 19-22: interpretCurrency currently converts value.amount to number
causing precision loss; change it to avoid Number(...) and instead produce an
exact, lossless representation (either a bigint in smallest units or an exact
decimal string) using value.amount (bigint) and
getCurrencyInfo(value.currency).decimals; specifically, read value.amount as
bigint, compute integer and fractional parts via bigint division and remainder
with 10**decimals, format and return an exact decimal string (or return the raw
bigint smallest-unit value and expose decimals) so downstream sorting/summing
use bigint/exact strings and only coerce to number at UI formatting boundaries;
update callers to expect the new return shape.
---
Outside diff comments:
In `@ensawards.org/data/incentive-programs/utils.ts`:
- Around line 29-36: Replace the implicit narrowing in the filter with an
explicit type predicate so the result is statically recognized as financial
awards: import AwardFinancial from data/awards/types (add AwardFinancial to the
existing import) and change the filter callback on
getAwardsByIncentiveProgramSlug(incentiveProgramSlug) to use a predicate
signature (e.g., (award): award is AwardFinancial => award.type ===
AwardTypes.FinancialAward) so that interpretCurrency(award.price) is safe
regardless of TypeScript version.
In `@ensawards.org/src/components/atoms/cards/referrerCard/rev-share/index.tsx`:
- Around line 136-146: The guard for additionalRevenueRequiredInUSD is
incomplete and you also construct a fragile inline Price by mixing fields from
editionRules.minBaseRevenueContribution and
referrer.totalBaseRevenueContribution; update the calculation so you first
compute a numeric delta only when both prices share the same currency (compare
editionRules.minBaseRevenueContribution.currency with
referrer.totalBaseRevenueContribution.currency) and clamp negative deltas to
zero, then pass that non-negative numeric amount and the correct currency into
interpretCurrency/usdFormatter to produce additionalRevenueRequiredInUSD;
finally, set userFacingAdditionalRevenueRequired to "$0.01" when the formatted
USD equals "$0.00" (after clamping) so the tooltip never shows negative values
or mixes currencies.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9012b5e4-f48e-424b-a347-bde8dc3552da
📒 Files selected for processing (16)
ensawards.org/data/awards/types.tsensawards.org/data/awards/utils.test.tsensawards.org/data/awards/utils.tsensawards.org/data/incentive-programs/ens-contract-naming-season/awards.tsensawards.org/data/incentive-programs/ens-contract-naming-season/index.tsensawards.org/data/incentive-programs/types.tsensawards.org/data/incentive-programs/utils.tsensawards.org/data/shared/currencies.tsensawards.org/data/shared/ensTokens.tsensawards.org/src/components/atoms/cards/contractNamingSeasonAwardCard/index.tsxensawards.org/src/components/atoms/cards/referralProgramEditionCard/rev-share/hero.tsxensawards.org/src/components/atoms/cards/referralProgramEditionCard/shared.tsxensawards.org/src/components/atoms/cards/referrerCard/pie-split/index.tsxensawards.org/src/components/atoms/cards/referrerCard/rev-share/index.tsxensawards.org/src/components/molecules/ReferralProgramEditionInfo.tsxensawards.org/src/utils/referralProgram.ts
💤 Files with no reviewable changes (2)
- ensawards.org/data/shared/ensTokens.ts
- ensawards.org/src/utils/referralProgram.ts
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ensawards.org/data/awards/utils.ts`:
- Line 41: interpretCurrency returns a number but the code compares
interpretedAmount to a bigint (0n); update the comparison in the boolean return
to use 0 (number) instead of 0n so the expression reads
Number.isFinite(interpretedAmount) && interpretedAmount > 0, referencing the
interpretedAmount variable and the interpretCurrency usage.
In `@ensawards.org/data/incentive-programs/utils.ts`:
- Around line 37-40: The reduce that computes totalFinancialAwards must validate
that every award.price.currency matches before summing to avoid mixing
currencies; update the logic in the incentiveProgramFinancialAwards reduction
(or extract to a helper used by totalFinancialAwards) to check
award.price.currency against the initial currency
(incentiveProgramFinancialAwards[0].price.currency) and throw an error (same
behavior as sortFinancialAwardsByPrice) if any mismatch is found, otherwise sum
amounts as currently implemented.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: dc139069-df94-4f5c-b116-1e2f2daaf7e1
📒 Files selected for processing (3)
ensawards.org/data/awards/utils.test.tsensawards.org/data/awards/utils.tsensawards.org/data/incentive-programs/utils.ts
Greptile SummaryThis PR moves ENS award values onto the SDK
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (6): Last reviewed commit: "Apply 06/25/26 GitHub review suggestion" | Re-trigger Greptile |
| const totalFinancialAwards = incentiveProgramFinancialAwards.reduce( | ||
| (acc, award) => ({ currency: acc.currency, amount: acc.amount + award.price.amount }), | ||
| { currency: incentiveProgramFinancialAwards[0].price.currency, amount: 0n }, | ||
| ); | ||
|
|
||
| return interpretCurrency(totalFinancialAwards); |
There was a problem hiding this comment.
Currency consistency not enforced at runtime
sumIncentiveProgramFinancialAwards initialises the accumulator currency from incentiveProgramFinancialAwards[0].price.currency and then sums every award's price.amount without checking whether subsequent awards share that currency. If awards in a program ever mix currencies, the function silently produces a numerically incorrect result — the ENS-wei and USDC-smallest-unit amounts would be added together and then interpreted under a single currency denomination. The test in index.test.ts guards this invariant, but the function itself never throws. sortFinancialAwardsByPrice (in the same PR) throws when currencies differ, so applying the same guard here would make the safety contract consistent.
There was a problem hiding this comment.
The way this function is constructed makes it impossible to sum amounts of different currencies if the added unit test passes (the invariant is met).
That's why it's not necessary to add the guard here.
There was a problem hiding this comment.
Fair point. If the unit test enforces that all awards within an incentive program share the same currency, and the data is controlled (not user-supplied), then the function's precondition is validated at the test boundary rather than at runtime. The current structure is reasonable.
The inconsistency with sortFinancialAwardsByPrice throwing on mixed currencies is worth noting, but you're right that it's not strictly necessary here given the invariant is covered by the test.
Tip: You can give me more context with .greptile/rules.md so I get this right next time.
Lite PR → Replace local definition of EnsTokens with ensnode-sdk types
Summary
EnsTokens(seeensawards.org/data/shared/ensTokens.ts) and replaced it withPricetype fromensnode-sdk, leveraging theparseEnsTokensfunction where necessaryparseReferralProgramCurrencyutility function to make the name more generic and moved it to a more appropriate place inensawards.org/data/shared/currencies.tsWhy
Testing
typecheck,lint, andtestcommands locally to ensure that the migration didn't break anything, and later confirmed that in our CI workflowPre-Review Checklist (Blocking)