-
Notifications
You must be signed in to change notification settings - Fork 0
Support Lit-claimed ORCID sandbox accounts #100
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: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -251,3 +251,51 @@ export async function getCrossChainOrcidAccountIdByOrcidId( | |
|
|
||
| return accountId as RepoDriverId; | ||
| } | ||
|
|
||
| /** | ||
| * Returns all possible ORCID account IDs for a given ORCID iD. | ||
| * | ||
| * This is needed for backwards compatibility: legacy ORCID sandbox accounts use | ||
| * sourceId=2 with "sandbox-" prefixed names, while Lit-claimed sandbox accounts | ||
| * use sourceId=4 with plain ORCID iDs. This function computes both possible | ||
| * account IDs so the resolver can try each one. | ||
| */ | ||
| export async function getAllPossibleOrcidAccountIds( | ||
| orcidId: string, | ||
| chainsToQuery: DbSchema[], | ||
| ): Promise<RepoDriverId[]> { | ||
| const availableChain = chainsToQuery.find( | ||
| (chain) => | ||
| dripsContracts[dbSchemaToChain[chain]] && | ||
| dripsContracts[dbSchemaToChain[chain]]!.repoDriver, | ||
| ); | ||
|
|
||
| if (!availableChain) { | ||
| throw new Error('No available chain with initialized contracts.'); | ||
| } | ||
|
|
||
| const { repoDriver } = dripsContracts[dbSchemaToChain[availableChain]]!; | ||
|
|
||
| const accountIds: RepoDriverId[] = []; | ||
|
|
||
| // Legacy account ID: sourceId=2, with the orcid string as provided | ||
| // (may include "sandbox-" prefix for legacy sandbox accounts) | ||
| const legacyAccountId = ( | ||
| await repoDriver.calcAccountId(2, ethers.toUtf8Bytes(orcidId)) | ||
| ).toString() as RepoDriverId; | ||
| accountIds.push(legacyAccountId); | ||
|
|
||
| // Lit sandbox account ID: sourceId=4, with plain ORCID (no "sandbox-" prefix) | ||
| const plainOrcid = orcidId.startsWith('sandbox-') | ||
| ? orcidId.slice('sandbox-'.length) | ||
| : orcidId; | ||
| const litSandboxAccountId = ( | ||
| await repoDriver.calcAccountId(4, ethers.toUtf8Bytes(plainOrcid)) | ||
| ).toString() as RepoDriverId; | ||
|
|
||
| if (litSandboxAccountId !== legacyAccountId) { | ||
| accountIds.push(litSandboxAccountId); | ||
| } | ||
|
|
||
| return accountIds; | ||
| } | ||
|
Comment on lines
+263
to
+301
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,11 +23,10 @@ import { | |
| } from '../utils/assert'; | ||
| import validateOrcidExists from '../orcid-account/validateOrcidExists'; | ||
| import fetchOrcidProfile from '../orcid-account/orcidApi'; | ||
| import { getCrossChainOrcidAccountIdByOrcidId } from '../common/dripsContracts'; | ||
| import { getAllPossibleOrcidAccountIds } from '../common/dripsContracts'; | ||
| import { extractOrcidFromAccountId } from '../orcid-account/orcidAccountIdUtils'; | ||
| import validateLinkedIdentitiesInput from './linkedIdentityValidators'; | ||
| import { validateChainsQueryArg } from '../utils/commonInputValidators'; | ||
| import type { RepoDriverId } from '../common/types'; | ||
| import { resolveTotalEarned } from '../common/commonResolverLogic'; | ||
| import getWithdrawableBalancesOnChain from '../utils/getWithdrawableBalances'; | ||
| import { PUBLIC_ERROR_CODES } from '../utils/formatError'; | ||
|
|
@@ -101,21 +100,29 @@ const linkedIdentityResolvers = { | |
| const exists = await validateOrcidExists(orcid); | ||
| if (!exists) return null; | ||
|
|
||
| // Try to find the account with the ORCID as provided (which may include sandbox- prefix) | ||
| const orcidAccountId: RepoDriverId = | ||
| await getCrossChainOrcidAccountIdByOrcidId(orcid, [ | ||
| chainToDbSchema[chain], | ||
| ]); | ||
| // Compute all possible account IDs for this ORCID. Legacy sandbox accounts | ||
| // use sourceId=2 with "sandbox-" prefixed names, while Lit-claimed sandbox | ||
| // accounts use sourceId=4 with plain ORCID iDs. | ||
| const candidateAccountIds = await getAllPossibleOrcidAccountIds(orcid, [ | ||
| chainToDbSchema[chain], | ||
| ]); | ||
|
|
||
| // Try each candidate account ID, return the first match found | ||
| for (const accountId of candidateAccountIds) { | ||
| assertIsLinkedIdentityId(accountId); | ||
| const identity = await linkedIdentitiesDataSource.getLinkedIdentityById( | ||
| accountId, | ||
| [chainToDbSchema[chain]], | ||
| ); | ||
|
|
||
| assertIsLinkedIdentityId(orcidAccountId); | ||
| const identity = await linkedIdentitiesDataSource.getLinkedIdentityById( | ||
| orcidAccountId, | ||
| [chainToDbSchema[chain]], | ||
| ); | ||
| if (identity) { | ||
| return toGqlLinkedIdentity(identity); | ||
| } | ||
| } | ||
|
Comment on lines
+111
to
+121
|
||
|
|
||
| return identity | ||
| ? toGqlLinkedIdentity(identity) | ||
| : toFakeUnclaimedOrcid(orcid, orcidAccountId, chain); | ||
| // No identity found — return a fake unclaimed entry using the first candidate | ||
| assertIsLinkedIdentityId(candidateAccountIds[0]); | ||
| return toFakeUnclaimedOrcid(orcid, candidateAccountIds[0], chain); | ||
|
Comment on lines
+123
to
+125
|
||
| }, | ||
| }, | ||
| OrcidLinkedIdentity: { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,38 +3,37 @@ | |||||||||
| import { isRepoDriverId } from '../utils/assert'; | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * ForgeId for ORCID in RepoDriver account IDs. | ||||||||||
| * Source IDs for ORCID in the contract. | ||||||||||
| * - 2: regular ORCID | ||||||||||
| * - 4: sandbox ORCID (Lit oracle uses a separate sourceId instead of a name prefix) | ||||||||||
|
Comment on lines
+7
to
+8
|
||||||||||
| * - 2: regular ORCID | |
| * - 4: sandbox ORCID (Lit oracle uses a separate sourceId instead of a name prefix) | |
| * - 2: legacy ORCID accounts (both production ORCID and legacy sandbox accounts with "sandbox-" prefix) | |
| * - 4: Lit-claimed sandbox ORCID accounts without the "sandbox-" prefix (use separate sourceId instead) |
Copilot
AI
Feb 15, 2026
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.
The test file tests/orcid-account/orcidAccountIdUtils.test.ts imports ORCID_FORGE_ID which was removed in this PR and replaced with ORCID_SOURCE_IDS. This change will break the existing test suite when this PR is merged. The test file needs to be updated to import and test ORCID_SOURCE_IDS instead, and the test should verify that it contains both 2 and 4.
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.
The function getAllPossibleOrcidAccountIds always adds sourceId=4 (Lit sandbox) candidates for production ORCID IDs that don't start with "sandbox-". However, based on the PR description, sourceId=4 is specifically for Lit-claimed sandbox accounts. This means for production ORCID IDs like "0000-0002-1825-0097", the function will compute and return a sourceId=4 account ID that would never be valid. Consider only computing the sourceId=4 account ID when the orcidId starts with "sandbox-" or when it looks like a sandbox ORCID pattern (starts with "0009-").