Skip to content

Conversation

@SergeyG-Solicy
Copy link
Contributor

@SergeyG-Solicy SergeyG-Solicy commented Feb 2, 2026

PR Type

Enhancement


Description

  • Added Human Passport identity integration for proof-of-personhood verification

  • Implemented point system for linking/unlinking Human Passport identities

  • Created HumanPassportProvider API client with caching and score verification

  • Extended identity management to support Human Passport identity operations


Diagram Walkthrough

flowchart LR
  HP["Human Passport API"] -->|verifyAddress| HumanPassportProvider["HumanPassportProvider<br/>Singleton Client"]
  HumanPassportProvider -->|cached verification| IdentityManager["IdentityManager<br/>Verify & Store"]
  IdentityManager -->|add/remove operations| GCRIdentityRoutines["GCRIdentityRoutines<br/>Apply Changes"]
  GCRIdentityRoutines -->|trigger incentives| IncentiveManager["IncentiveManager<br/>Award/Deduct Points"]
  IncentiveManager -->|update breakdown| PointSystem["PointSystem<br/>Track Points"]
  PointSystem -->|persist| GCRMain["GCRMain<br/>User Account"]
Loading

File Walkthrough

Relevant files
Enhancement
9 files
PointSystem.ts
Add Human Passport point tracking and award/deduct methods
+156/-12
GCRIdentityRoutines.ts
Implement Human Passport identity add and remove operations
+109/-0 
IncentiveManager.ts
Add Human Passport linking and unlinking incentive hooks 
+22/-0   
identityManager.ts
Add Human Passport payload verification and identity retrieval
+116/-7 
humanpassport.ts
Create Human Passport API client with caching and verification
+219/-0 
manageGCRRoutines.ts
Add RPC endpoints for Human Passport score and identities
+49/-0   
handleIdentityRequest.ts
Add Human Passport identity request handling and removal 
+6/-0     
GCR_Main.ts
Add Human Passport point breakdown field to account           
+1/-0     
IdentityTypes.ts
Define SavedHumanPassportIdentity type and update StoredIdentities
+29/-0   
Configuration changes
1 files
.env.example
Add Human Passport API configuration environment variables
+3/-0     

Summary by CodeRabbit

  • New Features

    • Human Passport support: users can link/unlink Human Passport identities, view associated scores/status, and automatically receive or lose reward points when linking or unlinking.
    • New runtime endpoints to fetch Human Passport scores and list linked Human Passport identities for verification flows.
  • Documentation

    • Example configuration updated with three new environment variables for Human Passport API integration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

Walkthrough

Adds end-to-end Human Passport (stamps) support: new env vars, a HumanPassportProvider client with caching, identity types and storage, verification and RPC endpoints, GCR add/remove handlers, and point/incentive integrations across identity and GCR stacks.

Changes

Cohort / File(s) Summary
Configuration
\.env.example
Added HUMAN_PASSPORT_API_URL, HUMAN_PASSPORT_API_KEY, HUMAN_PASSPORT_SCORER_ID.
Identity provider & tools
src/libs/identity/tools/humanpassport.ts
New HumanPassportProvider client with caching, TTL, verify/isHuman/getScore APIs, error handling, and default instance export.
Identity types & DB model
src/model/entities/types/IdentityTypes.ts, src/model/entities/GCRv2/GCR_Main.ts
Added SavedHumanPassportIdentity type, extended StoredIdentities with humanpassport[], and added points.breakdown.humanPassport?.
Identity manager & verification
src/libs/blockchain/gcr/gcr_routines/identityManager.ts
Added verifyHumanPassportPayload, getHumanPassportIdentities, getHumanPassportScore; extended getIdentities to accept humanpassport.
GCR identity apply/remove routines
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts
Added humanpassportadd / humanpassportremove cases, private handlers to upsert/remove humanpassport identities, uses HumanPassportProvider, and integrates first-link checks.
Incentives / Point system
src/features/incentive/PointSystem.ts, src/libs/blockchain/gcr/gcr_routines/IncentiveManager.ts
Added LINK_HUMAN_PASSPORT point value, awardHumanPassportPoints and deductHumanPassportPoints in PointSystem; added humanPassportLinked/humanPassportUnlinked hooks in IncentiveManager.
Network RPC & transaction handlers
src/libs/network/manageGCRRoutines.ts, src/libs/network/routines/transactions/handleIdentityRequest.ts
Added RPC getHumanPassportScore (forces refresh) and getHumanPassportIdentities; handle identity tx types humanpassport_identity_assign and humanpassport_identity_remove.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant IdentityMgr as IdentityManager
    participant HPProv as HumanPassportProvider
    participant GCRR as GCRIdentityRoutines
    participant Incentives as IncentiveManager
    participant Points as PointSystem

    Client->>IdentityMgr: verifyHumanPassportPayload(payload)
    IdentityMgr->>HPProv: verifyAddress(address, forceRefresh?)
    HPProv-->>IdentityMgr: HumanPassportVerification
    IdentityMgr-->>Client: SavedHumanPassportIdentity / result

    Client->>GCRR: apply("humanpassportadd", ...)
    GCRR->>HPProv: verifyAddress(address, use cache)
    HPProv-->>GCRR: verified data
    GCRR->>GCRR: upsert identity in accountGCR.identities.humanpassport
    GCRR->>Incentives: humanPassportLinked(userId, referralCode?)
    Incentives->>Points: awardHumanPassportPoints(userId, referralCode?)
    Points-->>Incentives: confirmation
    Incentives-->>GCRR: hook complete
    GCRR-->>Client: identity added & points awarded
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

Possible security concern

Suggested reviewers

  • cwilvx

Poem

🐰 I hopped in with stamps and a tiny cheer,
Verified an address and kept it near.
Cached the score, linked the proof in store,
Points popped up, the ledger sang some more.
Hooray — a hoppity stamp dance, soft and clear!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Added Human Passport identity integration' directly and accurately summarizes the main change: adding Human Passport proof-of-personhood verification with identity management, point system support, and RPC endpoints.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feature/human-passport

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.

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Feb 2, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
URL path injection

Description: User-controlled address is interpolated directly into the request path
(/v2/stamps/${this.scorerId}/score/${normalizedAddress}) without validating that it is a
canonical EVM address, which can enable path/query manipulation (e.g., crafted values
containing /, %2f, ?, or #) and cause unintended outbound requests against the configured
HUMAN_PASSPORT_API_URL (SSRF-style primitive within that host) or unexpected API
endpoints; validate/normalize strictly to 0x + 40 hex chars before calling verifyAddress.
humanpassport.ts [95-136]

Referred Code
async verifyAddress(
    address: string,
    forceRefresh = false,
): Promise<HumanPassportVerification> {
    const normalizedAddress = address.toLowerCase()

    // Check cache
    if (!forceRefresh) {
        const cached = this.getFromCache(normalizedAddress)
        if (cached) {
            log.debug(`[HumanPassportProvider] Cache hit for ${normalizedAddress}`)
            return cached
        }
    }

    // Fetch from API
    const apiUrl = `/v2/stamps/${this.scorerId}/score/${normalizedAddress}`

    try {
        const response = await this.http.get<RawScoreResponse>(apiUrl)
        const verification = this.transformResponse(response.data)


 ... (clipped 21 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit logs: New critical identity actions (Human Passport add/remove) are persisted and trigger
incentives without emitting an audit log containing the acting user
(editOperation.account), action, and outcome.

Referred Code
private static async applyHumanPassportIdentityAdd(
    editOperation: any,
    gcrMainRepository: Repository<GCRMain>,
    simulate: boolean,
): Promise<GCRResult> {
    const clientData = editOperation.data as { address: string; verificationMethod: "api" | "onchain" }
    const normalizedAddress = clientData.address.toLowerCase()

    // Fetch verified score from Human Passport API (uses cache from earlier verification)
    const provider = HumanPassportProvider.getInstance()
    const verification = await provider.verifyAddress(normalizedAddress)

    const savedIdentity: SavedHumanPassportIdentity = {
        address: verification.address,
        score: verification.score,
        passingScore: verification.passingScore,
        threshold: verification.threshold,
        stamps: verification.stamps,
        verificationMethod: clientData.verificationMethod,
        verifiedAt: verification.verifiedAt,
        expiresAt: verification.expirationTimestamp


 ... (clipped 69 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Sensitive data in logs: The new logs include full wallet addresses (and related score context) in debug/error
messages, which can be considered sensitive user identifiers and violate the “no sensitive
data in logs” requirement.

Referred Code
// Check cache
if (!forceRefresh) {
    const cached = this.getFromCache(normalizedAddress)
    if (cached) {
        log.debug(`[HumanPassportProvider] Cache hit for ${normalizedAddress}`)
        return cached
    }
}

// Fetch from API
const apiUrl = `/v2/stamps/${this.scorerId}/score/${normalizedAddress}`

try {
    const response = await this.http.get<RawScoreResponse>(apiUrl)
    const verification = this.transformResponse(response.data)

    // Cache the result
    this.setInCache(normalizedAddress, verification)

    return verification
} catch (error: any) {


 ... (clipped 14 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Missing input validation: The new Human Passport RPC handlers accept address from external inputs without validating
it as a proper EVM address before using it in API requests and identity workflows.

Referred Code
case "getHumanPassportScore": {
    const options = params[0]

    // Support both positional (string) and object ({ address }) param styles
    const address =
        typeof options === "string" ? options : options?.address
    // Always force refresh to get latest score from API
    const forceRefresh = true

    if (!address) {
        response.result = 400
        response.response = null
        response.extra = { error: "address is required" }
        break
    }

    try {
        const provider = HumanPassportProvider.getInstance()
        response.response = await provider.verifyAddress(
            address,
            forceRefresh,


 ... (clipped 9 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Unhandled axios errors: The new API client rethrows non-404/429 axios errors (throw error) which may propagate
without consistent handling/context across call sites, requiring verification that
upstream callers always catch and normalize these failures.

Referred Code
try {
    const response = await this.http.get<RawScoreResponse>(apiUrl)
    const verification = this.transformResponse(response.data)

    // Cache the result
    this.setInCache(normalizedAddress, verification)

    return verification
} catch (error: any) {
    log.error(`[HumanPassportProvider] API error for ${normalizedAddress}: ${error.message}`)

    if (error.response?.status === 404) {
        throw new Error(
            "User has not created a Human Passport. Direct them to passport.human.tech",
        )
    }

    if (error.response?.status === 429) {
        throw new Error("Human Passport API rate limit exceeded. Try again later.")
    }



 ... (clipped 2 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Leaky error messages: New user-facing responses and RPC extras directly surface error.message from external
API/axios errors, which may expose internal details depending on the thrown error content.

Referred Code
static async verifyHumanPassportPayload(
    payload: {
        address: string
        signature?: string
        verificationMethod: "api" | "onchain"
        chainId?: number
        referralCode?: string
    },
): Promise<{ success: boolean; message: string; data?: SavedHumanPassportIdentity }> {
    const { address, verificationMethod } = payload

    if (!address) {
        return {
            success: false,
            message: "Invalid Human Passport payload: missing address",
        }
    }

    try {
        // Verify score via Human Passport API
        const provider = HumanPassportProvider.getInstance()


 ... (clipped 42 lines)

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Feb 2, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Consider a more robust caching strategy

Replace the current in-memory cache in the HumanPassportProvider with a
persistent caching solution like Redis. This will prevent cache loss on server
restarts, improving performance and avoiding API rate-limiting issues.

Examples:

src/libs/identity/tools/humanpassport.ts [55]
    private readonly cache: Map<string, CachedScore> = new Map()

Solution Walkthrough:

Before:

// src/libs/identity/tools/humanpassport.ts

export class HumanPassportProvider {
    private static instance: HumanPassportProvider;
    private readonly cache: Map<string, CachedScore> = new Map();

    private constructor() {
        // ...
    }

    async verifyAddress(address: string): Promise<HumanPassportVerification> {
        const cached = this.getFromCache(address);
        if (cached) {
            return cached;
        }
        // ... fetch from API
        const verification = this.transformResponse(response.data);
        this.setInCache(address, verification);
        return verification;
    }
}

After:

// src/libs/identity/tools/humanpassport.ts
import { createClient } from 'redis'; // Example with Redis

export class HumanPassportProvider {
    private static instance: HumanPassportProvider;
    private readonly cacheClient; // e.g., Redis client

    private constructor() {
        this.cacheClient = createClient({ url: process.env.REDIS_URL });
        this.cacheClient.connect();
    }

    async verifyAddress(address: string): Promise<HumanPassportVerification> {
        const cached = await this.getFromCache(address);
        if (cached) {
            return cached;
        }
        // ... fetch from API
        const verification = this.transformResponse(response.data);
        await this.setInCache(address, verification);
        return verification;
    }
}
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies that the new HumanPassportProvider uses a non-persistent in-memory cache, which is a valid architectural concern for performance and reliability, and proposing a persistent cache is a significant improvement.

Medium
Possible issue
Add error handling for API calls
Suggestion Impact:The commit wrapped applyHumanPassportIdentityAdd logic, including the provider.verifyAddress() API call, in a try/catch and added logging plus a failure GCRResult return when an error occurs.

code diff:

@@ -1146,86 +1160,106 @@
         gcrMainRepository: Repository<GCRMain>,
         simulate: boolean,
     ): Promise<GCRResult> {
-        const clientData = editOperation.data as { address: string; verificationMethod: "api" | "onchain" }
-        const normalizedAddress = clientData.address.toLowerCase()
-
-        // Fetch verified score from Human Passport API (uses cache from earlier verification)
-        const provider = HumanPassportProvider.getInstance()
-        const verification = await provider.verifyAddress(normalizedAddress)
-
-        const savedIdentity: SavedHumanPassportIdentity = {
-            address: verification.address,
-            score: verification.score,
-            passingScore: verification.passingScore,
-            threshold: verification.threshold,
-            stamps: verification.stamps,
-            verificationMethod: clientData.verificationMethod,
-            verifiedAt: verification.verifiedAt,
-            expiresAt: verification.expirationTimestamp
-                ? new Date(verification.expirationTimestamp).getTime()
-                : null,
-        }
-
-        const accountGCR = await ensureGCRForUser(editOperation.account)
-
-        // Initialize humanpassport array if needed
-        if (!accountGCR.identities.humanpassport) {
-            accountGCR.identities.humanpassport = []
-        }
-
-        // Check if already linked
-        const existing = accountGCR.identities.humanpassport.find(
+        try {
+            const clientData = editOperation.data as { address: string; verificationMethod: "api" | "onchain" }
+            const normalizedAddress = clientData.address.toLowerCase()
+
+            // Fetch verified score from Human Passport API (uses cache from earlier verification)
+            const provider = HumanPassportProvider.getInstance()
+            const verification = await provider.verifyAddress(normalizedAddress)
+
+            const savedIdentity: SavedHumanPassportIdentity = {
+                address: verification.address,
+                score: verification.score,
+                passingScore: verification.passingScore,
+                threshold: verification.threshold,
+                stamps: verification.stamps,
+                verificationMethod: clientData.verificationMethod,
+                verifiedAt: verification.verifiedAt,
+                expiresAt: verification.expirationTimestamp
+                    ? new Date(verification.expirationTimestamp).getTime()
+                    : null,
+            }
+
+            const accountGCR = await ensureGCRForUser(editOperation.account)
+
+            // Initialize humanpassport array if needed
+            if (!accountGCR.identities.humanpassport) {
+                accountGCR.identities.humanpassport = []
+            }
+
+            // Global uniqueness check across all accounts
+            const isFirst = await this.isFirstConnection(
+                "humanpassport",
+                { address: normalizedAddress },
+                gcrMainRepository,
+                editOperation.account,
+            )
+
+            // Upsert: remove existing then add new
+            accountGCR.identities.humanpassport =
+                accountGCR.identities.humanpassport.filter(
+                    (hp: SavedHumanPassportIdentity) =>
+                        hp.address.toLowerCase() !== normalizedAddress,
+                )
+            accountGCR.identities.humanpassport.push(savedIdentity)
+
+            if (!simulate) {
+                await gcrMainRepository.save(accountGCR)
+
+                if (isFirst) {
+                    await IncentiveManager.humanPassportLinked(
+                        accountGCR.pubkey,
+                        editOperation.referralCode,
+                    )
+                }
+            }
+
+            return { success: true, message: "Human Passport identity added" }
+        } catch (error: any) {
+            log.error(`[GCRIdentityRoutines] Failed to add Human Passport identity: ${error.message}`)
+            return { success: false, message: error.message || "Failed to add Human Passport identity" }
+        }

Wrap the provider.verifyAddress() call and subsequent logic within
applyHumanPassportIdentityAdd in a try...catch block to handle potential API
errors gracefully.

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts [1144-1167]

     private static async applyHumanPassportIdentityAdd(
         editOperation: any,
         gcrMainRepository: Repository<GCRMain>,
         simulate: boolean,
     ): Promise<GCRResult> {
-        const clientData = editOperation.data as { address: string; verificationMethod: "api" | "onchain" }
-        const normalizedAddress = clientData.address.toLowerCase()
+        try {
+            const clientData = editOperation.data as { address: string; verificationMethod: "api" | "onchain" }
+            const normalizedAddress = clientData.address.toLowerCase()
+    
+            // Fetch verified score from Human Passport API (uses cache from earlier verification)
+            const provider = HumanPassportProvider.getInstance()
+            const verification = await provider.verifyAddress(normalizedAddress)
+    
+            const savedIdentity: SavedHumanPassportIdentity = {
+                address: verification.address,
+                score: verification.score,
+                passingScore: verification.passingScore,
+                threshold: verification.threshold,
+                stamps: verification.stamps,
+                verificationMethod: clientData.verificationMethod,
+                verifiedAt: verification.verifiedAt,
+                expiresAt: verification.expirationTimestamp
+                    ? new Date(verification.expirationTimestamp).getTime()
+                    : null,
+            }
+...
+            return { success: true, message: "Human Passport identity added" }
+        } catch (error: any) {
+            log.error(`[GCRIdentityRoutines] Failed to add Human Passport identity: ${error.message}`)
+            return {
+                success: false,
+                message: error.message || "Failed to add Human Passport identity",
+            }
+        }
+    }
 
-        // Fetch verified score from Human Passport API (uses cache from earlier verification)
-        const provider = HumanPassportProvider.getInstance()
-        const verification = await provider.verifyAddress(normalizedAddress)
-
-        const savedIdentity: SavedHumanPassportIdentity = {
-            address: verification.address,
-            score: verification.score,
-            passingScore: verification.passingScore,
-            threshold: verification.threshold,
-            stamps: verification.stamps,
-            verificationMethod: clientData.verificationMethod,
-            verifiedAt: verification.verifiedAt,
-            expiresAt: verification.expirationTimestamp
-                ? new Date(verification.expirationTimestamp).getTime()
-                : null,
-        }
-...
-

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies an unhandled exception from an API call in applyHumanPassportIdentityAdd, and the proposed try...catch block is a necessary addition for robust error handling.

Medium
Prevent incorrect point deduction on removal
Suggestion Impact:The removal routine was changed to explicitly check whether the specified Human Passport address exists and return early ("Identity not found") if it does not, ensuring humanPassportUnlinked is only called when an identity was present and removed.

code diff:

+    private static async applyHumanPassportIdentityRemove(
+        editOperation: any,
+        gcrMainRepository: Repository<GCRMain>,
+        simulate: boolean,
+    ): Promise<GCRResult> {
+        const data = editOperation.data as { address: string }
+        const normalizedAddress = data.address.toLowerCase()
+
+        const accountGCR = await gcrMainRepository.findOneBy({
+            pubkey: editOperation.account,
+        })
+
+        if (!accountGCR) {
+            return { success: false, message: "Account not found" }
+        }
+
+        if (!accountGCR.identities.humanpassport || accountGCR.identities.humanpassport.length === 0) {
+            return { success: false, message: "No Human Passport identities found" }
+        }
+
+        const addressExists = accountGCR.identities.humanpassport.some(
             (hp: SavedHumanPassportIdentity) =>
                 hp.address.toLowerCase() === normalizedAddress,
         )
 
-        const isFirst = !existing
-
-        // Upsert: remove existing then add new
+        if (!addressExists) {
+            return { success: false, message: "Identity not found" }
+        }
+
         accountGCR.identities.humanpassport =
             accountGCR.identities.humanpassport.filter(
                 (hp: SavedHumanPassportIdentity) =>
                     hp.address.toLowerCase() !== normalizedAddress,
             )
-        accountGCR.identities.humanpassport.push(savedIdentity)
 
         if (!simulate) {
             await gcrMainRepository.save(accountGCR)
 
-            if (isFirst) {
-                await IncentiveManager.humanPassportLinked(
-                    accountGCR.pubkey,
-                    editOperation.referralCode,
-                )
-            }
-        }
-
-        return { success: true, message: "Human Passport identity added" }
-    }
-
-    private static async applyHumanPassportIdentityRemove(
-        editOperation: any,
-        gcrMainRepository: Repository<GCRMain>,
-        simulate: boolean,
-    ): Promise<GCRResult> {
-        const data = editOperation.data as { address: string }
-        const normalizedAddress = data.address.toLowerCase()
-
-        const accountGCR = await ensureGCRForUser(editOperation.account)
-
-        if (!accountGCR.identities.humanpassport) {
-            return { success: true, message: "No Human Passport identities to remove" }
-        }
-
-        accountGCR.identities.humanpassport =
-            accountGCR.identities.humanpassport.filter(
-                (hp: SavedHumanPassportIdentity) =>
-                    hp.address.toLowerCase() !== normalizedAddress,
-            )
-
-        if (!simulate) {
-            await gcrMainRepository.save(accountGCR)
-
             await IncentiveManager.humanPassportUnlinked(accountGCR.pubkey)
         }

In applyHumanPassportIdentityRemove, only call
IncentiveManager.humanPassportUnlinked if an identity was actually found and
removed to prevent incorrect point deductions.

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts [1206-1233]

     private static async applyHumanPassportIdentityRemove(
         editOperation: any,
         gcrMainRepository: Repository<GCRMain>,
         simulate: boolean,
     ): Promise<GCRResult> {
         const data = editOperation.data as { address: string }
         const normalizedAddress = data.address.toLowerCase()
 
         const accountGCR = await ensureGCRForUser(editOperation.account)
 
-        if (!accountGCR.identities.humanpassport) {
+        if (!accountGCR.identities.humanpassport || accountGCR.identities.humanpassport.length === 0) {
             return { success: true, message: "No Human Passport identities to remove" }
         }
 
+        const initialCount = accountGCR.identities.humanpassport.length
         accountGCR.identities.humanpassport =
             accountGCR.identities.humanpassport.filter(
                 (hp: SavedHumanPassportIdentity) =>
                     hp.address.toLowerCase() !== normalizedAddress,
             )
+        const wasRemoved = accountGCR.identities.humanpassport.length < initialCount
 
         if (!simulate) {
             await gcrMainRepository.save(accountGCR)
 
-            await IncentiveManager.humanPassportUnlinked(accountGCR.pubkey)
+            if (wasRemoved) {
+                await IncentiveManager.humanPassportUnlinked(accountGCR.pubkey)
+            }
         }
 
         return { success: true, message: "Human Passport identity removed" }
     }

[Suggestion processed]

Suggestion importance[1-10]: 8

__

Why: This suggestion correctly identifies a logic bug where points would be deducted even if no identity was removed, and provides a correct fix to prevent incorrect point deductions.

Medium
Ensure required configuration is present
Suggestion Impact:Replaced warning logs for missing HUMAN_PASSPORT_API_KEY/HUMAN_PASSPORT_SCORER_ID with thrown errors and ensured scorerId assignment happens after validation.

code diff:

     private constructor() {
+        if (!DEFAULT_API_KEY) {
+            throw new Error("HUMAN_PASSPORT_API_KEY is not set in environment variables")
+        }
+
+        if (!DEFAULT_SCORER_ID) {
+            throw new Error("HUMAN_PASSPORT_SCORER_ID is not set in environment variables")
+        }
+
         this.scorerId = DEFAULT_SCORER_ID
-
-        if (!DEFAULT_API_KEY) {
-            log.warn("[HumanPassportProvider] HUMAN_PASSPORT_API_KEY not set")
-        }
-
-        if (!DEFAULT_SCORER_ID) {
-            log.warn("[HumanPassportProvider] HUMAN_PASSPORT_SCORER_ID not set")
-        }

In the HumanPassportProvider constructor, throw an error if the required
HUMAN_PASSPORT_API_KEY or HUMAN_PASSPORT_SCORER_ID environment variables are not
set, ensuring a fail-fast approach for missing configuration.

src/libs/identity/tools/humanpassport.ts [40-76]

     const DEFAULT_BASE_URL = process.env.HUMAN_PASSPORT_API_URL || "https://api.passport.xyz"
     const DEFAULT_SCORER_ID = process.env.HUMAN_PASSPORT_SCORER_ID || ""
     const DEFAULT_API_KEY = process.env.HUMAN_PASSPORT_API_KEY || ""
     const CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour
 
     /**
      * Human Passport API Client for Node
      *
      * Provides methods to verify Human Passport scores via the Stamps API v2.
      * Implements caching to reduce API calls.
      */
     export class HumanPassportProvider {
         private static instance: HumanPassportProvider
         private readonly http: AxiosInstance
         private readonly scorerId: string
         private readonly cache: Map<string, CachedScore> = new Map()
 
         private constructor() {
-            this.scorerId = DEFAULT_SCORER_ID
-
             if (!DEFAULT_API_KEY) {
-                log.warn("[HumanPassportProvider] HUMAN_PASSPORT_API_KEY not set")
+                throw new Error("HUMAN_PASSPORT_API_KEY is not set in environment variables")
             }
 
             if (!DEFAULT_SCORER_ID) {
-                log.warn("[HumanPassportProvider] HUMAN_PASSPORT_SCORER_ID not set")
+                throw new Error("HUMAN_PASSPORT_SCORER_ID is not set in environment variables")
             }
+
+            this.scorerId = DEFAULT_SCORER_ID
 
             this.http = axios.create({
                 baseURL: DEFAULT_BASE_URL,
                 timeout: 30000,
                 headers: {
                     "X-API-KEY": DEFAULT_API_KEY,
                     "Content-Type": "application/json",
                 },
             })
         }

[Suggestion processed]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that missing required environment variables should cause a startup failure rather than just a runtime warning, which is a best practice for robust application configuration.

Medium
General
Simplify identity mapping
Suggestion Impact:Replaced the for-loop/Array.isArray guard with a default empty array assignment and a .map() call to produce linkedHumanPassport.

code diff:

-        const linkedHumanPassport: { address: string; score: number; passingScore: boolean }[] = []
-        const humanPassportIdentities = await IdentityManager.getIdentities(userId, "humanpassport")
-        if (Array.isArray(humanPassportIdentities)) {
-            for (const hp of humanPassportIdentities) {
-                linkedHumanPassport.push({
-                    address: hp.address,
-                    score: hp.score || 0,
-                    passingScore: hp.passingScore || false,
-                })
-            }
-        }
+        const humanPassportIdentities: any[] = (await IdentityManager.getIdentities(userId, "humanpassport")) || []
+        const linkedHumanPassport = humanPassportIdentities.map(hp => ({
+            address: hp.address,
+            score: hp.score || 0,
+            passingScore: hp.passingScore || false,
+        }))

Refactor the humanPassportIdentities processing to use Array.prototype.map for a
more concise implementation, and default to an empty array to simplify the
logic.

src/features/incentive/PointSystem.ts [164-174]

-    const linkedHumanPassport: { address: string; score: number; passingScore: boolean }[] = []
-    const humanPassportIdentities = await IdentityManager.getIdentities(userId, "humanpassport")
-    if (Array.isArray(humanPassportIdentities)) {
-        for (const hp of humanPassportIdentities) {
-            linkedHumanPassport.push({
-                address: hp.address,
-                score: hp.score || 0,
-                passingScore: hp.passingScore || false,
-            })
-        }
-    }
+    const humanPassportIdentities: any[] = (await IdentityManager.getIdentities(userId, "humanpassport")) || []
+    const linkedHumanPassport = humanPassportIdentities.map(hp => ({
+        address: hp.address,
+        score: hp.score || 0,
+        passingScore: hp.passingScore || false,
+    }))

[Suggestion processed]

Suggestion importance[1-10]: 5

__

Why: The suggestion offers a valid and more concise way to handle the array mapping by using .map() and a default empty array, improving code readability and reducing boilerplate.

Low
  • Update

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: 9

🤖 Fix all issues with AI agents
In @.env.example:
- Around line 13-15: The .env.example is missing the HUMAN_PASSPORT_API_URL
variable used by HumanPassportProvider; add a new line entry named
HUMAN_PASSPORT_API_URL= (with a brief comment if desired) alongside
HUMAN_PASSPORT_API_KEY and HUMAN_PASSPORT_SCORER_ID so operators can override
the provider base URL; ensure the exact env name HUMAN_PASSPORT_API_URL matches
what HumanPassportProvider reads.

In `@src/features/incentive/PointSystem.ts`:
- Around line 1582-1611: In awardHumanPassportPoints, add the same identity link
check used in awardGithubPoints/awardDiscordPoints/awardTelegramPoints before
awarding points: after fetching userPointsWithIdentities via
getUserPointsInternal, verify the Human Passport identity is present (e.g. check
userPointsWithIdentities.identities.humanPassport or the equivalent identity
field) and if missing return a no-op RPCResponse (pointsAwarded: 0, totalPoints,
and a message like "Human Passport not linked") instead of calling
addPointsToGCR; only call addPointsToGCR with pointValues.LINK_HUMAN_PASSPORT
when the identity check passes.

In `@src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts`:
- Around line 1206-1233: The applyHumanPassportIdentityRemove routine currently
creates missing accounts and returns success for no-op removals; change it to
mirror other identity removals: fetch the account with
gcrMainRepository.findOneBy({ pubkey: editOperation.account }) (do not call
ensureGCRForUser) and return { success: false, message: "Account not found" } if
missing, check accountGCR.identities.humanpassport and if absent return {
success: false, message: "Identity not found" }, verify that an entry with
address.toLowerCase() exists before filtering and only proceed to filter, save
via gcrMainRepository.save(accountGCR) and call
IncentiveManager.humanPassportUnlinked(accountGCR.pubkey) when simulate is
false; otherwise return the appropriate success/failure messages to match
xm/ud/nomis behavior.
- Around line 1177-1182: The current first-connection check in
applyHumanPassportIdentityAdd uses a local-only check (existing in
accountGCR.identities.humanpassport) which allows the same humanpassport address
to earn points across multiple accounts; to fix, add "humanpassport" to the type
union handled by isFirstConnection and implement a handler branch in
isFirstConnection that queries gcrMainRepository for any other GCR record
containing a humanpassport with the same address (case-insensitive) excluding
the current account (pubkey/currentAccount), returning true only if no such
record exists; then modify applyHumanPassportIdentityAdd (and any helper) to
call isFirstConnection with type "humanpassport" and the address instead of
using the local existing check so the uniqueness check is global across
accounts.
- Around line 1152-1154: Wrap the external call
provider.verifyAddress(normalizedAddress) (from
HumanPassportProvider.getInstance()) in a try-catch inside the
GCRIdentityRoutines flow and convert failures into a proper GCRResult instead of
letting exceptions escape; specifically catch errors thrown by verifyAddress,
inspect error type/status (e.g. 404 -> return a GCRResult indicating “no
passport” or not verified, 429 -> return a GCRResult indicating rate-limited or
transient failure), and for unexpected errors return a GCRResult representing an
internal/error state while logging the original error for diagnostics; ensure
the rest of the routine uses that GCRResult rather than assuming verification
succeeded.

In `@src/libs/identity/tools/humanpassport.ts`:
- Around line 95-136: verifyAddress currently proceeds to call the API even when
credentials are missing, causing opaque Axios errors; add an early validation
guard at the start of verifyAddress that checks the instance's API key and
scorerId (the same values the constructor pulls from HUMAN_PASSPORT_API_KEY and
HUMAN_PASSPORT_SCORER_ID) and throw a clear Error like "Human Passport API
credentials missing: set HUMAN_PASSPORT_API_KEY and HUMAN_PASSPORT_SCORER_ID" if
either is empty/undefined, before any cache lookup or http.get; reference
verifyAddress, this.scorerId, and the http/http.get usage to locate where to add
the guard.

In `@src/libs/network/manageGCRRoutines.ts`:
- Around line 150-196: The RPC named getHumanPassportScore currently assigns the
full verification object returned by
HumanPassportProvider.getInstance().verifyAddress(address, forceRefresh) into
response.response; change this to return only the numeric score (e.g., set
response.response = verification.score) and keep the existing error handling, or
alternatively rename the RPC to getHumanPassportVerification if you want to keep
returning the full object; locate getHumanPassportScore and the verifyAddress
call to implement the extraction/rename consistently across callers.

In `@src/libs/network/routines/transactions/handleIdentityRequest.ts`:
- Around line 104-114: The human passport assignment branch must validate the
transaction sender before calling the external API: in the case handling
"humanpassport_identity_assign" check that (payload.payload as
HumanPassportIdentityData).address === sender and if not, return the same
rejection/invalid response used by other identity handlers; then call
IdentityManager.verifyHumanPassportPayload with two arguments (payload.payload
as HumanPassportIdentityData, sender) so the verifier can bind the address to
the sender. Update the "humanpassport_identity_assign" branch to perform this
address-equality check and pass sender into verifyHumanPassportPayload.

In `@src/model/entities/types/IdentityTypes.ts`:
- Around line 47-73: Update the SavedHumanPassportIdentity JSDoc comments to
explicitly state the timestamp units: change the comments for verifiedAt and
expiresAt to "milliseconds since Unix epoch (number)" and clarify expiresAt may
be null when not applicable; also add a short note that identityManager.ts and
GCRIdentityRoutines.ts perform conversion from API date strings to milliseconds
so callers should expect epoch ms in these fields.

Comment on lines 104 to 114
case "humanpassport_identity_assign":
return await IdentityManager.verifyHumanPassportPayload(
payload.payload as HumanPassportIdentityData,
)
case "xm_identity_remove":
case "pqc_identity_remove":
case "web2_identity_remove":
case "nomis_identity_remove":
case "ud_identity_remove":
case "humanpassport_identity_remove":
return {
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

rg -n "verifyHumanPassportPayload" --type ts -A 10 -B 2

Repository: kynesyslabs/node

Length of output: 2700


🏁 Script executed:

rg -n "IdentityManager" --type ts src/libs/network/routines/transactions/handleIdentityRequest.ts -C 3

Repository: kynesyslabs/node

Length of output: 2329


🏁 Script executed:

sed -n '383,420p' src/libs/blockchain/gcr/gcr_routines/identityManager.ts

Repository: kynesyslabs/node

Length of output: 1548


🏁 Script executed:

rg -n "verifyHumanPassportPayload" -A 30 src/libs/blockchain/gcr/gcr_routines/identityManager.ts

Repository: kynesyslabs/node

Length of output: 1329


🏁 Script executed:

sed -n '1,120p' src/libs/network/routines/transactions/handleIdentityRequest.ts

Repository: kynesyslabs/node

Length of output: 4820


🏁 Script executed:

rg -n "export.*handleIdentityRequest|function.*handleIdentityRequest" -A 20 src/libs/network/routines/transactions/handleIdentityRequest.ts | head -50

Repository: kynesyslabs/node

Length of output: 730


🏁 Script executed:

rg -n "HumanPassportIdentityData" --type ts -A 10 -B 2

Repository: kynesyslabs/node

Length of output: 3073


🏁 Script executed:

rg -n "verifyNomisPayload" --type ts -A 20 src/libs/blockchain/gcr/gcr_routines/identityManager.ts

Repository: kynesyslabs/node

Length of output: 821


Pass sender to verifyHumanPassportPayload and validate address binding.

The current implementation doesn't verify that payload.address matches the transaction sender, unlike other identity assignment handlers (xm, ud, pqc, web2). The external Human Passport API is called with an unverified address, allowing potential address spoofing.

Pass sender as a second parameter to verifyHumanPassportPayload and add validation that payload.address === sender before querying the API.

🤖 Prompt for AI Agents
In `@src/libs/network/routines/transactions/handleIdentityRequest.ts` around lines
104 - 114, The human passport assignment branch must validate the transaction
sender before calling the external API: in the case handling
"humanpassport_identity_assign" check that (payload.payload as
HumanPassportIdentityData).address === sender and if not, return the same
rejection/invalid response used by other identity handlers; then call
IdentityManager.verifyHumanPassportPayload with two arguments (payload.payload
as HumanPassportIdentityData, sender) so the verifier can bind the address to
the sender. Update the "humanpassport_identity_assign" branch to perform this
address-equality check and pass sender into verifyHumanPassportPayload.

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: 1

🤖 Fix all issues with AI agents
In `@src/libs/identity/tools/humanpassport.ts`:
- Around line 124-128: Update the user-facing error message URL: in
src/libs/identity/tools/humanpassport.ts locate the throw new Error(...) that
currently points users to "passport.human.tech" and replace that URL with
"https://app.passport.xyz/"; also make the same replacement for the identical
message in src/libs/blockchain/gcr/gcr_routines/identityManager.ts so both
throw/error messages consistently direct users to the correct signup URL.

Comment on lines 124 to 128
if (error.response?.status === 404) {
throw new Error(
"User has not created a Human Passport. Direct them to passport.human.tech",
)
}
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

🧩 Analysis chain

🌐 Web query:

Gitcoin Passport Human Passport user signup URL

💡 Result:

User signup / creation happens in the Human Passport (formerly Gitcoin Passport) app:

  • https://app.passport.xyz/ (connect wallet → “Sign in with Ethereum” creates your Passport if you don’t have one) [1][8]

🏁 Script executed:

# Search for API base URL references in the codebase
rg "api\.passport" --type ts --type js

# Also search for any passport.human.tech references
rg "passport\.human\.tech" --type ts --type js

# Search for any other passport URL patterns
rg "passport\.(xyz|tech)" --type ts --type js -A 2 -B 2

Repository: kynesyslabs/node

Length of output: 925


Update the error message URL to the correct user-facing endpoint.

The error message directs users to passport.human.tech, but the correct URL for Human Passport signup is https://app.passport.xyz/. This same incorrect URL also appears in src/libs/blockchain/gcr/gcr_routines/identityManager.ts and should be corrected there as well.

🤖 Prompt for AI Agents
In `@src/libs/identity/tools/humanpassport.ts` around lines 124 - 128, Update the
user-facing error message URL: in src/libs/identity/tools/humanpassport.ts
locate the throw new Error(...) that currently points users to
"passport.human.tech" and replace that URL with "https://app.passport.xyz/";
also make the same replacement for the identical message in
src/libs/blockchain/gcr/gcr_routines/identityManager.ts so both throw/error
messages consistently direct users to the correct signup URL.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 3, 2026

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: 1

🤖 Fix all issues with AI agents
In `@src/libs/blockchain/gcr/gcr_routines/identityManager.ts`:
- Around line 384-448: The method verifyHumanPassportPayload accepts sender,
payload.signature, payload.referralCode and payload.verificationMethod but never
uses them; update the implementation to either (A) implement the missing
behaviour: validate payload.signature (e.g., verify a signature binds the
returned verification.address to sender inside verifyHumanPassportPayload), pass
verificationMethod into HumanPassportProvider.verifyAddress or branch to onchain
verification when payload.verificationMethod === "onchain", and consume
referralCode if needed (e.g., attach to savedIdentity or call referral
processing), or (B) if not implementing now, add clear TODO comments inside
verifyHumanPassportPayload referencing sender, payload.signature,
payload.referralCode and payload.verificationMethod and log a security note
about pending signature-based binding; ensure you reference the
verifyHumanPassportPayload function, HumanPassportProvider.verifyAddress call,
and the SavedHumanPassportIdentity construction so reviewers can locate where to
add the signature check, verificationMethod branching, and referral handling.
🧹 Nitpick comments (1)
src/libs/blockchain/gcr/gcr_routines/identityManager.ts (1)

478-480: Consider logging errors for observability.

The empty catch block silently swallows all exceptions. While returning null is appropriate for the public API, logging the error would aid debugging and monitoring, consistent with the approach used in verifyHumanPassportPayload (line 442).

♻️ Suggested improvement
-        } catch {
+        } catch (error: any) {
+            log.warn(`[IdentityManager] Failed to fetch Human Passport score for ${address}: ${error.message}`)
             return null
         }

Comment on lines +384 to +448
static async verifyHumanPassportPayload(
payload: {
address: string
signature?: string
verificationMethod: "api" | "onchain"
chainId?: number
referralCode?: string
},
sender: string,
): Promise<{ success: boolean; message: string; data?: SavedHumanPassportIdentity }> {
const { address, verificationMethod } = payload

if (!address) {
return {
success: false,
message: "Invalid Human Passport payload: missing address",
}
}

try {
// Verify score via Human Passport API
const provider = HumanPassportProvider.getInstance()
const verification = await provider.verifyAddress(address)

if (!verification.passingScore) {
return {
success: false,
message: `Human Passport score ${verification.score} below threshold (${verification.threshold}). ` +
`User needs to verify more stamps at https://app.passport.xyz/. Transaction not applied.`,
}
}

// Build saved identity
const savedIdentity: SavedHumanPassportIdentity = {
address: verification.address,
score: verification.score,
passingScore: verification.passingScore,
threshold: verification.threshold,
stamps: verification.stamps,
verificationMethod: verificationMethod,
chainId: payload.chainId,
verifiedAt: verification.verifiedAt,
expiresAt: verification.expirationTimestamp
? new Date(verification.expirationTimestamp).getTime()
: null,
}

log.info(
`[IdentityManager] Human Passport verified: ${address} ` +
`(score: ${verification.score}, stamps: ${verification.stamps.length})`,
)

return {
success: true,
message: `Human Passport identity verified with score ${verification.score}`,
data: savedIdentity,
}
} catch (error: any) {
log.error(`[IdentityManager] Human Passport verification failed: ${error.message}`)
return {
success: false,
message: error.message || "Failed to verify Human Passport identity",
}
}
}
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:

# First, check the file structure and find where this method is defined
cd /tmp && find . -name "identityManager.ts" -type f 2>/dev/null | head -5

Repository: kynesyslabs/node

Length of output: 42


🏁 Script executed:

# Search for verificationMethod usage in context of HumanPassport
rg -n "verificationMethod" --type ts -B 2 -A 2 | head -60

Repository: kynesyslabs/node

Length of output: 3146


🏁 Script executed:

# Search for referralCode usage
rg -n "referralCode" --type ts -B 2 -A 2

Repository: kynesyslabs/node

Length of output: 29249


🏁 Script executed:

# Search for calls to verifyHumanPassportPayload
rg -n "verifyHumanPassportPayload" --type ts -B 3 -A 3

Repository: kynesyslabs/node

Length of output: 1530


🏁 Script executed:

# Check if sender parameter is used elsewhere in the file
rg -n "sender" src/libs/blockchain/gcr/gcr_routines/identityManager.ts -B 1 -A 1

Repository: kynesyslabs/node

Length of output: 1743


🏁 Script executed:

# Look for TODO or FIXME comments related to these parameters
rg -n "TODO|FIXME" src/libs/blockchain/gcr/gcr_routines/identityManager.ts -B 1 -A 1

Repository: kynesyslabs/node

Length of output: 405


🏁 Script executed:

# Find the type definition for the payload parameter
rg -n "SavedHumanPassportIdentity|verifyHumanPassportPayload" --type ts -B 5 | grep -E "interface|type|export" | head -20

Repository: kynesyslabs/node

Length of output: 1387


🏁 Script executed:

# Check the full method implementation and immediate context
sed -n '380,450p' src/libs/blockchain/gcr/gcr_routines/identityManager.ts

Repository: kynesyslabs/node

Length of output: 2861


🏁 Script executed:

# Look for SavedHumanPassportIdentity definition and usage
cat -n src/model/entities/types/IdentityTypes.ts | sed -n '54,75p'

Repository: kynesyslabs/node

Length of output: 1083


🏁 Script executed:

# Check how referralCode flows through the GCRIdentityRoutines for humanpassport
rg -n "humanPassport|HumanPassport" src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts -B 3 -A 5 | grep -A 8 "referralCode"

Repository: kynesyslabs/node

Length of output: 284


🏁 Script executed:

# Look for signature validation patterns in the codebase
rg -n "signature.*verify|verifySignature|verify.*signature" --type ts | head -20

Repository: kynesyslabs/node

Length of output: 2292


🏁 Script executed:

# Check if there are any comments or context about future work around these parameters
rg -n "signature|sender|referralCode|verificationMethod" src/libs/blockchain/gcr/gcr_routines/identityManager.ts -B 1 -A 1 | tail -50

Repository: kynesyslabs/node

Length of output: 2068


🏁 Script executed:

# Check if there's any branch logic or conditional around verificationMethod that might differ for "api" vs "onchain"
sed -n '384,450p' src/libs/blockchain/gcr/gcr_routines/identityManager.ts | grep -i "onchain\|api\|verificationMethod" -A 2 -B 2

Repository: kynesyslabs/node

Length of output: 885


🏁 Script executed:

# Check the HumanPassportProvider to see if it handles verificationMethod differently
rg -n "class HumanPassportProvider|verifyAddress" --type ts -B 2 -A 8 | head -40

Repository: kynesyslabs/node

Length of output: 3288


Unused parameters indicate incomplete implementation or missing functionality.

Several parameters are accepted but not implemented:

  1. sender (line 392) — documented as "for binding verification" but never referenced in the method
  2. payload.signature (line 387) — optional field accepted but never validated
  3. payload.referralCode (line 390) — accepted but ignored (processed elsewhere in the call chain)
  4. payload.verificationMethod (line 388) — stored in the result but both "api" and "onchain" values use identical verification logic; the HumanPassportProvider.verifyAddress() method doesn't accept or differentiate based on this parameter

If these fields represent intended functionality, consider either implementing them or adding TODO comments explaining their planned use. If signature-based binding to the sender address was intended, this could represent a security gap.

🤖 Prompt for AI Agents
In `@src/libs/blockchain/gcr/gcr_routines/identityManager.ts` around lines 384 -
448, The method verifyHumanPassportPayload accepts sender, payload.signature,
payload.referralCode and payload.verificationMethod but never uses them; update
the implementation to either (A) implement the missing behaviour: validate
payload.signature (e.g., verify a signature binds the returned
verification.address to sender inside verifyHumanPassportPayload), pass
verificationMethod into HumanPassportProvider.verifyAddress or branch to onchain
verification when payload.verificationMethod === "onchain", and consume
referralCode if needed (e.g., attach to savedIdentity or call referral
processing), or (B) if not implementing now, add clear TODO comments inside
verifyHumanPassportPayload referencing sender, payload.signature,
payload.referralCode and payload.verificationMethod and log a security note
about pending signature-based binding; ensure you reference the
verifyHumanPassportPayload function, HumanPassportProvider.verifyAddress call,
and the SavedHumanPassportIdentity construction so reviewers can locate where to
add the signature check, verificationMethod branching, and referral handling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants