-
Notifications
You must be signed in to change notification settings - Fork 2
Added Human Passport identity integration #658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: testnet
Are you sure you want to change the base?
Conversation
WalkthroughAdds 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 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 |
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
|||||||||||||||||||||||||
PR Code Suggestions ✨Explore these optional code suggestions:
|
|||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
rg -n "verifyHumanPassportPayload" --type ts -A 10 -B 2Repository: kynesyslabs/node
Length of output: 2700
🏁 Script executed:
rg -n "IdentityManager" --type ts src/libs/network/routines/transactions/handleIdentityRequest.ts -C 3Repository: kynesyslabs/node
Length of output: 2329
🏁 Script executed:
sed -n '383,420p' src/libs/blockchain/gcr/gcr_routines/identityManager.tsRepository: kynesyslabs/node
Length of output: 1548
🏁 Script executed:
rg -n "verifyHumanPassportPayload" -A 30 src/libs/blockchain/gcr/gcr_routines/identityManager.tsRepository: kynesyslabs/node
Length of output: 1329
🏁 Script executed:
sed -n '1,120p' src/libs/network/routines/transactions/handleIdentityRequest.tsRepository: kynesyslabs/node
Length of output: 4820
🏁 Script executed:
rg -n "export.*handleIdentityRequest|function.*handleIdentityRequest" -A 20 src/libs/network/routines/transactions/handleIdentityRequest.ts | head -50Repository: kynesyslabs/node
Length of output: 730
🏁 Script executed:
rg -n "HumanPassportIdentityData" --type ts -A 10 -B 2Repository: kynesyslabs/node
Length of output: 3073
🏁 Script executed:
rg -n "verifyNomisPayload" --type ts -A 20 src/libs/blockchain/gcr/gcr_routines/identityManager.tsRepository: 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| if (error.response?.status === 404) { | ||
| throw new Error( | ||
| "User has not created a Human Passport. Direct them to passport.human.tech", | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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 2Repository: 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.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
nullis appropriate for the public API, logging the error would aid debugging and monitoring, consistent with the approach used inverifyHumanPassportPayload(line 442).♻️ Suggested improvement
- } catch { + } catch (error: any) { + log.warn(`[IdentityManager] Failed to fetch Human Passport score for ${address}: ${error.message}`) return null }
| 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", | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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 -5Repository: 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 -60Repository: kynesyslabs/node
Length of output: 3146
🏁 Script executed:
# Search for referralCode usage
rg -n "referralCode" --type ts -B 2 -A 2Repository: kynesyslabs/node
Length of output: 29249
🏁 Script executed:
# Search for calls to verifyHumanPassportPayload
rg -n "verifyHumanPassportPayload" --type ts -B 3 -A 3Repository: 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 1Repository: 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 1Repository: 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 -20Repository: 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.tsRepository: 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 -20Repository: 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 -50Repository: 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 2Repository: 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 -40Repository: kynesyslabs/node
Length of output: 3288
Unused parameters indicate incomplete implementation or missing functionality.
Several parameters are accepted but not implemented:
sender(line 392) — documented as "for binding verification" but never referenced in the methodpayload.signature(line 387) — optional field accepted but never validatedpayload.referralCode(line 390) — accepted but ignored (processed elsewhere in the call chain)payload.verificationMethod(line 388) — stored in the result but both"api"and"onchain"values use identical verification logic; theHumanPassportProvider.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.



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
File Walkthrough
9 files
Add Human Passport point tracking and award/deduct methodsImplement Human Passport identity add and remove operationsAdd Human Passport linking and unlinking incentive hooksAdd Human Passport payload verification and identity retrievalCreate Human Passport API client with caching and verificationAdd RPC endpoints for Human Passport score and identitiesAdd Human Passport identity request handling and removalAdd Human Passport point breakdown field to accountDefine SavedHumanPassportIdentity type and update StoredIdentities1 files
Add Human Passport API configuration environment variablesSummary by CodeRabbit
New Features
Documentation