Skip to content

Conversation

@HakobP-Solicy
Copy link
Contributor

@HakobP-Solicy HakobP-Solicy commented Dec 30, 2025

Summary by CodeRabbit

  • New Features

    • Nomis score linking/unlinking for EVM and Solana with automatic point awards and deductions.
    • Nomis identities can be imported, listed, and managed for linked wallets.
    • Points breakdown now shows per-chain Nomis score totals.
  • Improvements

    • Validation and error responses for Nomis inputs and linkage flows.
    • New endpoints to fetch Nomis scores and identities with clearer success/partial/failure payloads.

✏️ Tip: You can customize this high-level summary in your review settings.

@tcsenpai
Copy link
Contributor

Your trial has ended! 😢

To keep getting reviews, activate your plan here.

Got questions about plans or want to see if we can extend your trial? Talk to our founders here.😎

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 30, 2025

Walkthrough

Adds Nomis score linking, fetching, and point-awarding/deduction across the incentive stack: PointSystem, IncentiveManager hooks, GCR identity routines, IdentityManager, a NomisIdentityProvider, Nomis API client, RPC handlers, and types/models to persist per-chain nomisScores and identities.

Changes

Cohort / File(s) Summary
Point System & Incentive Hooks
src/features/incentive/PointSystem.ts, src/libs/blockchain/gcr/gcr_routines/IncentiveManager.ts
New public methods to award/deduct Nomis score points, chain validation, duplicate-link prevention, mapping score→points, breakdown.nomisScores updates; IncentiveManager adds nomisLinked/nomisUnlinked delegations.
GCR Identity Routines & IdentityManager
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts, src/libs/blockchain/gcr/gcr_routines/identityManager.ts, src/libs/network/routines/transactions/handleIdentityRequest.ts
Added Nomis upsert/remove handlers, address normalization, isFirstConnection updated for "nomis", IdentityManager gains verifyNomisPayload and getNomisIdentities; transaction handler routes nomis_identity_assign/remove.
Nomis Identity Provider & API Client
src/libs/identity/providers/nomisIdentityProvider.ts, src/libs/identity/tools/nomis.ts
New NomisIdentityProvider with getWalletScore/listIdentities, caching and wallet-link checks; NomisApiClient implements cross-chain score fetch with request/options models and error handling.
Types & Models
src/model/entities/types/IdentityTypes.ts, src/types/nomis-augmentations.d.ts, src/model/entities/GCRv2/GCR_Main.ts
New NomisWalletIdentity/SavedNomisIdentity, StoredIdentities.nomis mapping, ambient GCREdit augmentations for nomis payloads, and GCR_Main.points.breakdown.nomisScores added.
Network RPCs
src/libs/network/manageGCRRoutines.ts
Added getNomisScore and getNomisIdentities RPC handlers delegating to NomisIdentityProvider with input validation and error handling.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Incentive as IncentiveManager
    participant PointSystem
    participant GCRRepo as GCR Repository
    participant NomisProvider as NomisIdentityProvider
    rect rgba(200,220,255,0.6)
      Note over Client,PointSystem: Award Nomis Score (new flow)
      Client->>Incentive: nomisLinked(userId, chain, score, referral?)
      Incentive->>PointSystem: awardNomisScorePoints(userId, chain, score, referral?)
      PointSystem->>GCRRepo: fetch account & linked wallets
      GCRRepo-->>PointSystem: account data (including linked wallets)
      PointSystem->>NomisProvider: (optional) getWalletScore / verify identity
      alt validation fails
        PointSystem-->>Client: 400 error (invalid chain / wallet not linked)
      else success
        PointSystem->>GCRRepo: apply nomis upsert / addPointsToGCR(type: "nomisScores")
        GCRRepo-->>PointSystem: persist result
        PointSystem-->>Client: success RPC with updated breakdown.nomisScores
      end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Fixed udIdentityManager issues #530 — Touches PointSystem and identity/points retrieval logic; overlaps with changes to breakdown and identity returns.
  • Ud identities #481 — Adds a new identity type (UD) across PointSystem, IncentiveManager, and GCR routines using similar hooks/patterns.
  • Backup & Restore #404 — Modifies PointSystem/IncentiveManager and award/deduct hook patterns; similar surface area changes.

Suggested labels

Possible security concern, Review effort 5/5

Suggested reviewers

  • cwilvx

Poem

🐰 A Nomis score hops into place,
Linked wallets, points, and cross-chain grace,
I nibble bytes and tally the scores,
Hopping through code, opening doors,
A carrot of features—hop, hooray! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Integrated Nomis Identity' directly summarizes the main change: adding comprehensive Nomis identity integration across multiple system components.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-nomis-integration

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (9)
src/model/entities/GCRv2/GCR_Main.ts (1)

43-43: Consider adding optional marker for backward compatibility.

The nomisScores field should be marked as optional (like udDomains on line 36) to maintain backward compatibility with existing records that don't have this field yet.

🔎 Proposed fix
-            nomisScores: { [chain: string]: number }
+            nomisScores?: { [chain: string]: number }
src/libs/identity/tools/nomis.ts (4)

60-60: Remove unused field.

The useMockData field is declared but never initialized or used anywhere in the class.

🔎 Proposed fix
     private readonly http: AxiosInstance
     private readonly defaultScoreType: number
     private readonly defaultDeadlineOffset: number
-    private readonly useMockData: boolean

101-101: Hardcoded timeout overrides configured value.

The timeout is hardcoded to 30000ms here, which differs from the configurable NOMIS_API_TIMEOUT_MS (default 10000ms) set in the constructor on line 80. This inconsistency could cause confusion.

🔎 Proposed fix

Consider using the configured timeout or document why this endpoint needs a different timeout:

-        const timeout = 30000
+        const timeout = this.http.defaults.timeout || 30000

97-99: Consider adding address format validation.

The current validation only checks if the address exists but doesn't validate its format. For EVM addresses, consider checking if it's a valid hex address with 0x prefix and 40 hex characters. For Solana, consider validating base58 format.


112-112: Document hardcoded chain IDs.

The scoredChains array contains hardcoded chain IDs without documentation. Consider adding a comment explaining what these chains are (e.g., "Ethereum mainnet, Optimism, BSC, Polygon, Mantle, Base, Arbitrum, Linea") or making this configurable.

src/model/entities/types/IdentityTypes.ts (1)

31-45: Consider consolidating duplicate interfaces.

SavedNomisIdentity appears to be identical to NomisWalletIdentity. If there's no semantic difference between them (e.g., one for API payloads, one for storage), consider using a single interface or having one extend/reference the other to reduce duplication.

src/libs/blockchain/gcr/gcr_routines/identityManager.ts (1)

288-310: Add validation for payload fields beyond presence checks.

The verifyNomisPayload method only validates that chain, subchain, and address are present but doesn't validate the remaining required fields. Consider adding:

  • Range validation for score and scoreType
  • Format validation for lastSyncedAt (ensure valid timestamp/date string)
  • Address format validation to ensure it's a valid blockchain address
  • Chain/subchain validation against the supported chains (available in the chains object and chainIds config)

This would align with the more comprehensive validation pattern used in verifyPayload.

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts (1)

971-980: Consider extracting address normalization to a shared utility.

This normalization logic is duplicated in nomisIdentityProvider.ts (lines 138-148). Extracting to a shared utility would ensure consistent behavior and reduce maintenance burden.

src/features/incentive/PointSystem.ts (1)

1465-1472: Add JSDoc clarifying the expected score range and rounding behavior.

The function assumes score is in the 0-1 range (multiplied by 100 to produce 0-100 percentage). The implementation is correct, but should be documented with a JSDoc comment explaining the expected input format and how toFixed(0) rounding affects edge cases (e.g., 0.795 becomes 5 points, while 0.794 becomes 4 points). This prevents future confusion and ensures maintainers understand the dependency on Nomis API score format.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between db55486 and 6907b1b.

📒 Files selected for processing (11)
  • src/features/incentive/PointSystem.ts
  • src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts
  • src/libs/blockchain/gcr/gcr_routines/IncentiveManager.ts
  • src/libs/blockchain/gcr/gcr_routines/identityManager.ts
  • src/libs/identity/providers/nomisIdentityProvider.ts
  • src/libs/identity/tools/nomis.ts
  • src/libs/network/manageGCRRoutines.ts
  • src/libs/network/routines/transactions/handleIdentityRequest.ts
  • src/model/entities/GCRv2/GCR_Main.ts
  • src/model/entities/types/IdentityTypes.ts
  • src/types/nomis-augmentations.d.ts
🧰 Additional context used
🧬 Code graph analysis (6)
src/libs/network/routines/transactions/handleIdentityRequest.ts (2)
src/libs/blockchain/gcr/gcr_routines/identityManager.ts (1)
  • IdentityManager (53-389)
src/model/entities/types/IdentityTypes.ts (1)
  • NomisWalletIdentity (3-19)
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts (3)
src/libs/blockchain/gcr/gcr_routines/ensureGCRForUser.ts (1)
  • ensureGCRForUser (8-33)
src/model/entities/types/IdentityTypes.ts (2)
  • SavedNomisIdentity (31-45)
  • NomisWalletIdentity (3-19)
src/libs/blockchain/gcr/gcr_routines/IncentiveManager.ts (1)
  • IncentiveManager (9-196)
src/libs/network/manageGCRRoutines.ts (1)
src/libs/identity/providers/nomisIdentityProvider.ts (1)
  • NomisIdentityProvider (24-163)
src/libs/blockchain/gcr/gcr_routines/identityManager.ts (1)
src/model/entities/types/IdentityTypes.ts (1)
  • NomisWalletIdentity (3-19)
src/libs/identity/tools/nomis.ts (1)
src/libs/identity/providers/nomisIdentityProvider.ts (1)
  • NomisImportOptions (16-22)
src/features/incentive/PointSystem.ts (2)
src/model/entities/types/IdentityTypes.ts (1)
  • NomisWalletIdentity (3-19)
src/libs/blockchain/gcr/gcr_routines/identityManager.ts (1)
  • IdentityManager (53-389)
🔇 Additional comments (23)
src/libs/identity/tools/nomis.ts (2)

135-154: LGTM!

Error handling is well-implemented with proper logging, validation of response structure, and informative error messages.


5-46: LGTM!

Type definitions are well-structured with appropriate use of optional fields and generic types.

src/libs/network/routines/transactions/handleIdentityRequest.ts (3)

12-12: LGTM!

Import addition is appropriate for the new Nomis identity handling.


95-98: LGTM!

The Nomis identity assignment handling follows the same pattern as other identity types, properly delegating to the identity manager for verification.


102-102: LGTM!

The Nomis identity removal case is consistent with other identity removal handlers.

src/libs/network/manageGCRRoutines.ts (2)

99-130: LGTM!

The getNomisScore handler properly validates required inputs, constructs options, and handles errors with appropriate HTTP status codes. Error handling correctly captures both Error instances and other thrown values.


132-145: LGTM!

The getNomisIdentities handler follows the same clean error handling pattern as getNomisScore.

src/libs/blockchain/gcr/gcr_routines/IncentiveManager.ts (2)

165-180: LGTM!

The nomisLinked hook follows the established pattern of other identity linking hooks in this class, properly delegating to the PointSystem.


182-195: LGTM!

The nomisUnlinked hook is consistent with other unlinking hooks, properly handling the deduction flow.

src/types/nomis-augmentations.d.ts (1)

1-33: LGTM!

The type augmentations are properly structured and extend the SDK types to support Nomis identities. The module augmentation syntax is correct, and the types align with the Nomis identity structures defined elsewhere in the codebase.

src/model/entities/types/IdentityTypes.ts (2)

3-19: LGTM!

The NomisWalletIdentity interface is well-structured with appropriate required and optional fields. The metadata object with index signature allows for extensibility.


103-107: LGTM!

The nomis field properly extends StoredIdentities with the same nested structure as xm identities, and correctly marked as optional for backward compatibility.

src/libs/blockchain/gcr/gcr_routines/identityManager.ts (2)

25-25: LGTM!

Import is correctly added for Nomis identity support.


354-364: LGTM!

The signature extension to include "nomis" is consistent with the existing pattern for other identity types.

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts (2)

940-968: LGTM!

The isFirstConnection logic correctly differentiates between web3 (using xm root key) and nomis identity types with parameterized JSONB queries.


857-870: LGTM!

The new nomisadd and nomisremove switch cases follow the established pattern for other identity operations.

src/libs/identity/providers/nomisIdentityProvider.ts (4)

77-95: LGTM!

The wallet linkage validation correctly checks the xm identities with case-insensitive address comparison for EVM chains.


97-117: LGTM!

The identity record construction properly handles optional fields with appropriate fallback values.


119-136: LGTM!

The flattening logic correctly transforms the nested chain/subchain structure into a flat array with context preserved.


138-148: LGTM!

The address normalization includes proper validation for empty addresses and chain-appropriate transformations.

src/features/incentive/PointSystem.ts (3)

92-115: LGTM!

The Nomis identity collection logic correctly mirrors the existing Web3 wallet iteration pattern, properly adding chain/subchain context to each identity.


270-277: LGTM!

The nomisScores handling in addPointsToGCR follows the established pattern for other breakdown types.


1285-1404: LGTM!

The awardNomisScorePoints method has thorough validation: chain allowlist, Twitter linkage requirement, corresponding wallet linkage per chain, and duplicate prevention. The point calculation delegation to getNomisPointsByScore is clean.

Comment on lines +998 to +1000
if (!chain || !subchain || !address || !score) {
return { success: false, message: "Invalid Nomis identity payload" }
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validation rejects valid score of 0.

The condition !score evaluates to true when score === 0, which is a valid Nomis score. This would incorrectly reject identities with a score of zero.

🔎 Proposed fix
-        if (!chain || !subchain || !address || !score) {
+        if (!chain || !subchain || !address || typeof score !== "number") {
             return { success: false, message: "Invalid Nomis identity payload" }
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!chain || !subchain || !address || !score) {
return { success: false, message: "Invalid Nomis identity payload" }
}
if (!chain || !subchain || !address || typeof score !== "number") {
return { success: false, message: "Invalid Nomis identity payload" }
}
🤖 Prompt for AI Agents
In src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts around lines 998
to 1000, the validation uses `!score` which incorrectly rejects a legitimate
score of 0; update the condition to explicitly check for missing/invalid score
(e.g., `score === undefined || score === null` or `typeof score !== 'number'`)
instead of `!score`, keeping the other checks for chain, subchain and address
intact so a zero score is accepted as valid.

identity.address,
)

const accountGCR = await ensureGCRForUser(editOperation.account)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove operation uses ensureGCRForUser instead of querying existing account.

Using ensureGCRForUser in a remove operation will create a new account if one doesn't exist, which is inconsistent with other remove operations (e.g., applyXmIdentityRemove at line 133 uses findOneBy). Additionally, the score for point deduction is taken from the request payload (identity.score) rather than the stored identity, which could allow manipulation of deducted points.

🔎 Proposed fix
-        const accountGCR = await ensureGCRForUser(editOperation.account)
+        const accountGCR = await gcrMainRepository.findOneBy({
+            pubkey: editOperation.account,
+        })
+
+        if (!accountGCR) {
+            return { success: false, message: "Account not found" }
+        }

For the score issue, retrieve the stored score before removal:

+        const storedIdentity = chainBucket.find(existing => {
+            const existingAddress = this.normalizeNomisAddress(
+                identity.chain,
+                existing.address,
+            )
+            return existingAddress === normalizedAddress
+        })
+
+        if (!storedIdentity) {
+            return { success: false, message: "Nomis identity not found" }
+        }
+
         // ... filter logic ...
 
         if (!simulate) {
             await gcrMainRepository.save(accountGCR)
 
             await IncentiveManager.nomisUnlinked(
                 accountGCR.pubkey,
                 identity.chain,
-                identity.score,
+                storedIdentity.score,
             )
         }

Also applies to: 1110-1114

🤖 Prompt for AI Agents
In src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts around lines 1077
and also 1110-1114, the remove flow is calling ensureGCRForUser which can create
an account instead of querying an existing one and is using identity.score from
the request to compute point deductions; change the logic to query the existing
account and identity (e.g., use findOneBy or the existing repository find
method) and if the account or identity is missing, handle it as a not-found/skip
error instead of creating one; once you have the stored identity record, read
its score from the database and use that stored score for any point deductions,
then proceed with removal; update both occurrences (around 1077 and 1110-1114)
accordingly.

Comment on lines +377 to +388
static async getNomisIdentities(
address: string,
chain: string,
subchain: string,
) {
if (!chain && !subchain) {
return null
}

const data = await this.getIdentities(address, "nomis")
return (data[chain] || {})[subchain] || []
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n src/libs/blockchain/gcr/gcr_routines/identityManager.ts | head -50

Repository: kynesyslabs/node

Length of output: 1911


🏁 Script executed:

sed -n '320-335p' src/libs/blockchain/gcr/gcr_routines/identityManager.ts

Repository: kynesyslabs/node

Length of output: 111


🏁 Script executed:

cat -n src/libs/blockchain/gcr/gcr_routines/identityManager.ts | sed -n '320,335p'

Repository: kynesyslabs/node

Length of output: 603


🏁 Script executed:

cat -n src/libs/blockchain/gcr/gcr_routines/identityManager.ts | sed -n '377,390p'

Repository: kynesyslabs/node

Length of output: 462


🏁 Script executed:

rg -n "getXmIdentities|getNomisIdentities" --type=ts -B2 -A2 src/

Repository: kynesyslabs/node

Length of output: 1643


🏁 Script executed:

cat -n src/libs/network/manageGCRRoutines.ts | sed -n '45,50p'

Repository: kynesyslabs/node

Length of output: 283


🏁 Script executed:

cat -n src/libs/network/manageGCRRoutines.ts | sed -n '132,145p'

Repository: kynesyslabs/node

Length of output: 625


🏁 Script executed:

rg "IdentityManager\.getNomisIdentities|IdentityManager\.getXmIdentities" --type=ts -B2 -A2

Repository: kynesyslabs/node

Length of output: 42


🏁 Script executed:

fd -e test.ts -e spec.ts | head -20

Repository: kynesyslabs/node

Length of output: 42


🏁 Script executed:

rg "getNomisIdentities|getXmIdentities" --type=ts -C5

Repository: kynesyslabs/node

Length of output: 3407


🏁 Script executed:

rg "\.getNomisIdentities\(|\.getXmIdentities\(" --type=ts

Repository: kynesyslabs/node

Length of output: 42


🏁 Script executed:

cat -n src/libs/blockchain/gcr/gcr_routines/identityManager.ts | sed -n '250,290p'

Repository: kynesyslabs/node

Length of output: 1759


🏁 Script executed:

cat -n src/libs/blockchain/gcr/gcr_routines/identityManager.ts | sed -n '1,100p'

Repository: kynesyslabs/node

Length of output: 3780


🏁 Script executed:

rg "getIdentities\(" --type=ts -B2 -A2 | head -60

Repository: kynesyslabs/node

Length of output: 4409


🏁 Script executed:

cat -n src/libs/blockchain/gcr/gcr_routines/identityManager.ts | sed -n '307,340p'

Repository: kynesyslabs/node

Length of output: 1418


🏁 Script executed:

cat -n src/libs/blockchain/gcr/gcr_routines/identityManager.ts | sed -n '200,220p'

Repository: kynesyslabs/node

Length of output: 934


Guard condition uses AND instead of OR, should validate both chain and subchain are present.

Line 382 checks if (!chain && !subchain) which only returns null when BOTH are missing. This should be if (!chain || !subchain) to properly validate that both parameters are required before accessing the nested object. The same issue exists in getXmIdentities at line 325. Note: these methods do not appear to be directly called in the codebase currently.

🤖 Prompt for AI Agents
In src/libs/blockchain/gcr/gcr_routines/identityManager.ts around lines 377 to
388 (and similarly at line ~325 for getXmIdentities), the guard uses `if (!chain
&& !subchain)` which only returns when both are missing; change the check to `if
(!chain || !subchain)` so the function returns null when either parameter is
absent before accessing nested properties, and update the corresponding
getXmIdentities guard the same way; keep behavior of returning an empty array
when keys are present.

Comment on lines +45 to +53
if (existing) {
if (options.forceRefresh) {
log.info(
`[NomisIdentityProvider] Skipping refresh for ${normalizedWallet} (chain=${chain}/${subchain}) until identity removal`,
)
}

return existing
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

forceRefresh option has no effect when identity exists.

When existing is found, the code logs "Skipping refresh" but returns the cached identity regardless of forceRefresh value. If refresh is intentionally disabled, the log message is misleading. If refresh should work, the logic needs adjustment.

🔎 Suggested clarification

Either remove the forceRefresh option from NomisImportOptions if refresh is not supported, or implement actual refresh logic:

         if (existing) {
-            if (options.forceRefresh) {
-                log.info(
-                    `[NomisIdentityProvider] Skipping refresh for ${normalizedWallet} (chain=${chain}/${subchain}) until identity removal`,
-                )
-            }
-
-            return existing
+            if (!options.forceRefresh) {
+                return existing
+            }
+            // Proceed to fetch fresh score from API
         }
🤖 Prompt for AI Agents
In src/libs/identity/providers/nomisIdentityProvider.ts around lines 45 to 53,
the current logic always returns the cached identity and logs "Skipping refresh"
even when options.forceRefresh is true; update the implementation so
forceRefresh has effect: if options.forceRefresh is true, bypass the cached
return and perform the refresh/fetch flow (and update the cache) instead of
returning existing, and change the log message to reflect when refresh is
actually skipped; alternatively, if refresh is not supported, remove
forceRefresh from NomisImportOptions and callers, and update types/tests
accordingly.

@tcsenpai
Copy link
Contributor

Your trial has ended! 😢

To keep getting reviews, activate your plan here.

Got questions about plans or want to see if we can extend your trial? Talk to our founders here.😎

@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/features/incentive/PointSystem.ts (2)

1285-1404: Consider adding identity existence verification for consistency.

Unlike awardUdDomainPoints (lines 1118-1135) which verifies the domain exists in account.identities.ud before awarding points, this method doesn't verify the Nomis identity exists in account.identities.nomis for the given chain. This verification prevents race conditions where points could be awarded before the identity is properly persisted.

🔎 Suggested enhancement
         const existingNomisScoreOnChain =
             userPointsWithIdentities.breakdown.nomisScores?.[chain]

         if (existingNomisScoreOnChain != null) {
             const updatedPoints = await this.getUserPointsInternal(userId)

             return {
                 result: 400,
                 response: {
                     pointsAwarded: 0,
                     totalPoints: updatedPoints.totalPoints,
                     message: nomisScoreAlreadyLinkedMessage,
                 },
                 require_reply: false,
                 extra: {},
             }
         }

+        // Verify Nomis identity exists in GCR to prevent race conditions
+        const account = await ensureGCRForUser(userId)
+        const nomisIdentityExists = account.identities.nomis?.[chain] && 
+            Object.keys(account.identities.nomis[chain]).some(subchain => {
+                const identities = account.identities.nomis[chain][subchain]
+                return Array.isArray(identities) && identities.length > 0
+            })
+
+        if (!nomisIdentityExists) {
+            return {
+                result: 400,
+                response: {
+                    pointsAwarded: 0,
+                    totalPoints: userPointsWithIdentities.totalPoints,
+                    message: `Cannot award points: Nomis identity for ${chain} not found in GCR identities`,
+                },
+                require_reply: false,
+                extra: {},
+            }
+        }

         const pointsToAward = this.getNomisPointsByScore(nomisScore)

1485-1492: Consider adding input validation for robustness.

The method doesn't validate that score is within an expected range. If the score parameter is negative, greater than 1, or NaN, it could lead to incorrect point calculations.

🔎 Suggested defensive check
 private getNomisPointsByScore(score: number): number {
+    // Validate score is in expected range (assuming 0-1)
+    if (typeof score !== 'number' || isNaN(score)) {
+        log.warn(`Invalid Nomis score: ${score}, defaulting to minimum points`)
+        return 1
+    }
+    if (score < 0 || score > 1) {
+        log.warn(`Nomis score out of range: ${score}, clamping to [0, 1]`)
+        score = Math.max(0, Math.min(1, score))
+    }
+
     const formattedScore = Number((score * 100).toFixed(0))
     if (formattedScore >= 80) return 5
     if (formattedScore >= 60) return 4
     if (formattedScore >= 40) return 3
     if (formattedScore >= 20) return 2
     return 1
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6907b1b and fb4be35.

📒 Files selected for processing (1)
  • src/features/incentive/PointSystem.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/features/incentive/PointSystem.ts (3)
src/model/entities/types/IdentityTypes.ts (1)
  • NomisWalletIdentity (3-19)
src/libs/blockchain/gcr/gcr_routines/identityManager.ts (1)
  • IdentityManager (53-389)
src/libs/blockchain/gcr/gcr_routines/ensureGCRForUser.ts (1)
  • ensureGCRForUser (8-33)
🔇 Additional comments (4)
src/features/incentive/PointSystem.ts (4)

92-115: LGTM: Nomis identity extraction logic is correct.

The nested iteration and mapping properly flattens the Nomis identities structure while preserving chain and subchain information.


165-208: LGTM: getUserPointsInternal correctly extended for Nomis.

The additions are consistent with existing identity patterns and include proper fallback handling.


221-277: LGTM: addPointsToGCR properly extended for Nomis scores.

The implementation follows the established pattern for per-chain point tracking used by web3Wallets and udDomains.


1413-1483: LGTM: Pre-deduction check has been addressed.

The implementation now includes the missing check at lines 1432-1449, verifying that Nomis points exist for the chain before deduction. This prevents negative breakdown values and matches the pattern used in other deduct methods like deductTwitterPoints and deductUdDomainPoints.

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