Conversation
* chore: bump mobile app version to 2.7.1 * fix last deployed timestamp --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Justin Hernandez <[email protected]>
* refactor: use singular ETHERSCAN_API_KEY in .env Etherscan has unified all keys of associated explorers like Celoscan into a singular key rather than different keys for different networks. * refactor: use one .env instead of separate .env.test + .env files * refactor: deploy contracts with runs of 1000 instead of 200 Decreases gas cost of function calls on deployed contracts * clean: remove duplicate/redundant deploy modules + scripts * clean: cleanup empty script file * refactor: cleanup default network of scripts Read network from .env instead of using defaults of alfajores (outdated) or staging * clean: remove references to Alfajores, replace with Sepolia * chore: add default .env variables * chore: update build-all script to include aardhaar circuit * chore: update broken Powers of Tau download link (use iden3) * chore: remove duplicate script * fix: use stable version 18 for disclose circuits * test: update test import paths to allow for .ts version of generateProof * test: fix broken tests * test: uncomment critical code for registration, change error names to updated names, fix broken import paths, update disclose tests for new scope generation/handling * fix: broken import path * test: fix Airdrop tests to use V2 logic * docs: update docs for necessary prerequisite programs * chore: yarn prettier formatting * fix: CI errors occuring when deploying contracts as can't read .env Using a dummy key for CI builds * chore: yarn prettier * refactor: change runs to 100000
* fix: qrcode peer dependencies * chore: yarn
* feat: add constructor with _disableInitializers as per OZ best practices https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#initializing-the-implementation-contract * docs: update layout and add section names * chore: run yarn prettier
* address lint issues * different approach
* fix: ios symlink * replace ios symlinks with files
* feat: generate second address * update setting store
* add retry to logic to ci workflows * simplify retry logic
* update lock files * use isUserRegisteredWithAlternativeCSCA * update lock * fix building release version * aadhaar fix for public keys * fix aadhaar check and add tess * fix test types * fix mocked data * coderabbit feedback * update tests and remove cruft * update lock and aar file * fix script and building aar file, add assets for recovery
* bump android version * remove spurious title
|
Important Review skippedBot user detected. To trigger a single review, invoke the You can disable this status message by setting the WalkthroughThis PR introduces infrastructure upgrades, testnet migration from Alfajores to Sepolia, smart contract enhancements with new verification root contracts, mobile app feature additions (points address derivation), and extensive OpenSSL framework header additions. Version bumps mobile app to 2.7.2, updates CI workflows with retry mechanisms, and reorganizes contract deployments. Changes
Sequence DiagramsequenceDiagram
participant App as Mobile App
participant Provider as Auth Provider
participant Store as Settings Store
participant Proving as Proof Validation
participant Mnemonic as Mnemonic (Keychain)
rect rgb(200, 220, 255)
Note over App,Mnemonic: getOrGeneratePointsAddress() Flow
App->>Provider: getOrGeneratePointsAddress()
alt pointsAddress exists in store
Provider-->>App: return cached pointsAddress
else pointsAddress not found
Provider->>Mnemonic: retrieveOrCreateMnemonic()
Mnemonic-->>Provider: mnemonic string
Provider->>Provider: _generateAddressFromMnemonic(mnemonic, index=1)
Note over Provider: Derives HD address using fixed path
Provider->>Store: setPointsAddress(derivedAddress)
Store-->>Provider: ✓ stored
Provider-->>App: return derivedAddress
end
end
rect rgb(200, 255, 220)
Note over Proving: Document Validation with CSCA Handling
App->>Proving: validateDocument()
Proving->>Proving: isUserRegisteredWithAlternativeCSCA()
alt registration confirmed
Proving->>Proving: getAlternativeCSCA()
alt Aadhaar doc
Note over Proving: Returns Record of public keys
else passport/id_card
Note over Proving: Returns alternative_csca from store
end
Proving->>Proving: reStorePassportDataWithRightCSCA()
Proving->>Proving: emit DOCUMENT_VALIDATED
else unregistered
Proving->>Proving: skip CSCA restoration
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Areas requiring extra attention:
Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
1 similar comment
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 33
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
.github/workflows/release-calendar.yml (1)
373-379: Add error handling to production PR creation to match staging pattern.The production PR creation (lines 373-379) lacks error handling present in staging (lines 206-218). While
set -euo pipefailwill still cause step failure, staging's explicit error wrapper provides clearer failure visibility and consistent logging. For production deployments, this inconsistency should be resolved:TITLE="Release to Production - ${PR_DATE}" echo "Creating PR with title: ${TITLE} from staging with ${COMMITS_AHEAD} commits ahead." - gh pr create \ + if ! gh pr create \ --base main \ --head staging \ --title "${TITLE}" \ --label release \ --label automated \ --label production \ - --body-file pr_body.md + --body-file pr_body.md; then + echo "❌ ERROR: Failed to create production release PR" + exit 1 + fi + + echo "✅ Production release PR created successfully"app/tests/src/screens/WebViewScreen.test.tsx (1)
11-23: Inconsistent React aliasing pattern—app/jest.setup.js not aligned with WebViewScreen.test.tsx changes.WebViewScreen.test.tsx uses
const ReactModule = require('react')(line 12), but the global Jest setup inapp/jest.setup.jsstill usesconst React = require('react')across all its mocks (react-native-webview, react-native-safe-area-context, react-native-svg, @/layouts/ExpandableBottomLayout, @selfxyz/mobile-sdk-alpha/components, @tamagui/lucide-icons, @/components/WebViewFooter).If this is part of a broader React runtime aliasing pattern migration, the global setup must be updated to maintain consistency. Otherwise, the selective change in WebViewScreen.test.tsx creates confusion about the intended pattern.
Update
app/jest.setup.jsto apply theReactModulealiasing consistently across all mocks where React is used.contracts/contracts/abstract/SelfVerificationRoot.sol (1)
65-68: Add zero-address validation for the hub contract.The constructor should validate that
identityVerificationHubV2Addressis not the zero address to prevent deployment with an invalid hub reference, which would make the contract non-functional.Apply this diff:
constructor(address identityVerificationHubV2Address, string memory scopeSeed) { + if (identityVerificationHubV2Address == address(0)) { + revert("SelfVerificationRoot: Invalid hub address"); + } _identityVerificationHubV2 = IIdentityVerificationHubV2(identityVerificationHubV2Address); _scope = _calculateScope(address(this), scopeSeed, _getPoseidonAddress()); }
🧹 Nitpick comments (3)
contracts/hardhat.config.ts (1)
35-88: Update deployment documentation to remove Alfajores network references.The Alfajores network configuration has been successfully removed from hardhat.config.ts, but the deployment example comments in
contracts/ignition/modules/deployTestSelfVerificationRoot.tsstill reference the now-removed--network alfajoresflag. Update these comment blocks to usecelo-sepoliainstead, so developers copying examples won't attempt to deploy to a non-existent network.contracts/contracts/abstract/SelfVerificationRoot.sol (1)
195-210: Document the implications of returning address(0) for local/development networks.When
_getPoseidonAddress()returnsaddress(0)for unsupported chains,_calculateScope()will return 0 (line 226), resulting in_scope = 0. This means all proofs on local/development networks will use scope 0. Consider documenting this behavior more explicitly, especially if scope 0 has special security implications for testing vs production environments.app/android/react-native-passport-reader/android/build.gradle (1)
8-11: No critical compatibility issues found; align NFC module minSdkVersion with app requirement.React Native 0.80 requires API 24 (Android 7.0) minimum, and the main app correctly declares this. However, the NFC module sets minSdkVersion to 21, which is inconsistent—though not breaking, since gradle will use the app's API 24 during build.
Verification shows the code is well-implemented for Android 14/15:
- No deprecated file permission APIs (scoped storage compliant)
- No notification or broadcast receiver complexity
- Correct
PendingIntent.FLAG_MUTABLEusage for Android 12+Update
app/android/react-native-passport-reader/android/build.gradleline 10 fromminSdkVersion 21tominSdkVersion 24for consistency with the app's declared minimum.
| - name: Install NDK | ||
| if: inputs.platform != 'ios' && steps.ndk-cache.outputs.cache-hit != 'true' | ||
| run: | | ||
| max_attempts=5 | ||
| attempt=1 | ||
|
|
||
| # Install NDK | ||
| while [ $attempt -le $max_attempts ]; do | ||
| echo "Attempt $attempt of $max_attempts to install NDK..." | ||
| if sdkmanager "ndk;${{ env.ANDROID_NDK_VERSION }}"; then | ||
| echo "Successfully installed NDK" | ||
| break | ||
| fi | ||
| echo "Failed to install NDK on attempt $attempt" | ||
| if [ $attempt -eq $max_attempts ]; then | ||
| echo "All attempts to install NDK failed" | ||
| exit 1 | ||
| fi | ||
| # Exponential backoff: 2^attempt seconds | ||
| wait_time=$((2 ** attempt)) | ||
| echo "Waiting $wait_time seconds before retrying..." | ||
| sleep $wait_time | ||
| attempt=$((attempt + 1)) | ||
| done | ||
|
|
||
| # Install CMake (required for native module builds) | ||
| echo "Installing CMake..." | ||
| attempt=1 | ||
| while [ $attempt -le $max_attempts ]; do | ||
| echo "Attempt $attempt of $max_attempts to install CMake..." | ||
| if sdkmanager "cmake;3.22.1"; then | ||
| echo "Successfully installed CMake" | ||
| break | ||
| fi | ||
| echo "Failed to install CMake on attempt $attempt" | ||
| if [ $attempt -eq $max_attempts ]; then | ||
| echo "All attempts to install CMake failed" | ||
| exit 1 | ||
| fi | ||
| # Exponential backoff: 2^attempt seconds | ||
| wait_time=$((2 ** attempt)) | ||
| echo "Waiting $wait_time seconds before retrying..." | ||
| sleep $wait_time | ||
| attempt=$((attempt + 1)) | ||
| done | ||
| uses: nick-fields/retry@v3 | ||
| with: | ||
| timeout_minutes: 15 | ||
| max_attempts: 5 | ||
| retry_wait_seconds: 10 | ||
| command: sdkmanager "ndk;${{ env.ANDROID_NDK_VERSION }}" | ||
|
|
||
| - name: Install CMake | ||
| if: inputs.platform != 'ios' && steps.ndk-cache.outputs.cache-hit != 'true' | ||
| uses: nick-fields/retry@v3 | ||
| with: | ||
| timeout_minutes: 10 | ||
| max_attempts: 5 | ||
| retry_wait_seconds: 10 | ||
| command: sdkmanager "cmake;3.22.1" |
There was a problem hiding this comment.
CMake install skips on fresh runners
Tying the CMake install step to steps.ndk-cache.outputs.cache-hit means we skip sdkmanager "cmake;3.22.1" whenever the NDK cache restores. Because we only cache ${ANDROID_SDK_ROOT}/ndk/${ANDROID_NDK_VERSION}, new runners start without CMake, the cache still “hits,” and Gradle later fails when it needs that exact CMake version. Please decouple the CMake step from the NDK cache (or add a dedicated cache) so the install always runs when required.
- - name: Install CMake
- if: inputs.platform != 'ios' && steps.ndk-cache.outputs.cache-hit != 'true'
+ - name: Install CMake
+ if: inputs.platform != 'ios'
uses: nick-fields/retry@v3
with:
timeout_minutes: 10
max_attempts: 5
retry_wait_seconds: 10
command: sdkmanager "cmake;3.22.1"🤖 Prompt for AI Agents
.github/workflows/mobile-deploy.yml around lines 1060 to 1076: the CMake install
step is gated on the NDK cache hit which causes CMake to be skipped on fresh
runners even when not present; remove the dependency on
steps.ndk-cache.outputs.cache-hit for the CMake step (i.e. use the same platform
check as NDK: if: inputs.platform != 'ios') or add a separate cache/result check
for a dedicated CMake cache and gate the step on that; ensure the sdkmanager
"cmake;3.22.1" command always runs when CMake might be missing (or when the
cmake-cache indicates a miss).
| export async function getOrGeneratePointsAddress(): Promise<string> { | ||
| const pointsAddress = useSettingStore.getState().pointsAddress; | ||
| if (pointsAddress) { | ||
| return pointsAddress; | ||
| } | ||
|
|
||
| const mnemonicData = await _getSecurely<Mnemonic>( | ||
| keychainOptions => loadOrCreateMnemonic(keychainOptions), | ||
| str => JSON.parse(str), | ||
| { requireAuth: true }, | ||
| ); | ||
|
|
||
| if (!mnemonicData?.data?.phrase) { | ||
| throw new Error( | ||
| 'Failed to retrieve mnemonic for points address generation', | ||
| ); | ||
| } | ||
|
|
||
| const pointsAddr = _generateAddressFromMnemonic(mnemonicData.data.phrase, 1); | ||
|
|
||
| useSettingStore.getState().setPointsAddress(pointsAddr); | ||
| return pointsAddr; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
Consider security implications of plaintext address storage.
While biometric authentication is required to derive the address initially, the resulting address is stored in plaintext in AsyncStorage via setPointsAddress. This creates a persistent record that could be:
- Extracted from device backups
- Linked to user activity if the address is used on-chain
If the points address will have significant financial value or needs privacy protection, consider:
- Regenerating it on-demand rather than persisting
- Encrypting it before storage
- Documenting the privacy/security tradeoffs
Additionally, this function is exported from the module but not added to the IAuthContext interface (lines 204-215). If this is intended as a public API, add it to the context; otherwise, prefix with underscore or keep internal-only.
🏁 Script executed:
#!/bin/bash
# Examine the authProvider.tsx file around the function and interface definitions
echo "=== Checking lines 204-215 for IAuthContext interface ==="
sed -n '204,215p' app/src/providers/authProvider.tsx
echo -e "\n=== Checking lines 337-359 for getOrGeneratePointsAddress function ==="
sed -n '337,359p' app/src/providers/authProvider.tsx
echo -e "\n=== Checking export status of getOrGeneratePointsAddress ==="
rg -n "export.*getOrGeneratePointsAddress" app/src/providers/authProvider.tsx
echo -e "\n=== Searching for setPointsAddress implementation ==="
rg -n "setPointsAddress" app/src/providers/authProvider.tsx -A 3 -B 3Length of output: 1616
🏁 Script executed:
#!/bin/bash
# Find useSettingStore implementation to understand storage mechanism
echo "=== Locating useSettingStore ==="
fd -t f "*.ts" -o "*.tsx" | xargs rg -l "useSettingStore\s*=" | head -5
echo -e "\n=== Searching for useSettingStore definition ==="
rg -n "export.*useSettingStore|const useSettingStore" --type=ts --type=tsx -A 5 | head -40
echo -e "\n=== Checking if setPointsAddress uses any encryption ==="
rg -n "setPointsAddress" --type=ts --type=tsx -C 5Length of output: 357
🏁 Script executed:
#!/bin/bash
# Check for any encryption utilities or security measures
echo "=== Searching for encryption or security-related imports ==="
rg -n "encrypt|Encrypt|crypto|Crypto|secure|Secure" app/src/providers/authProvider.tsx
echo -e "\n=== Checking full file structure around lines 200-220 and 330-370 ==="
wc -l app/src/providers/authProvider.tsx
echo -e "\n=== Viewing the area around IAuthContext ==="
sed -n '195,230p' app/src/providers/authProvider.tsx
echo -e "\n=== Viewing the area around getOrGeneratePointsAddress ==="
sed -n '330,370p' app/src/providers/authProvider.tsxLength of output: 3175
🏁 Script executed:
#!/bin/bash
# Examine settingStore to understand storage mechanism
echo "=== Viewing settingStore.ts ==="
cat app/src/stores/settingStore.ts | head -100
echo -e "\n=== Searching for pointsAddress in settingStore ==="
rg -n "pointsAddress" app/src/stores/settingStore.ts -B 3 -A 3Length of output: 4132
🏁 Script executed:
#!/bin/bash
# Check if AsyncStorage is used and any encryption
echo "=== Checking for AsyncStorage usage in settingStore ==="
rg -n "AsyncStorage" app/src/stores/settingStore.ts
echo -e "\n=== Checking for encryption utilities ==="
rg -n "encrypt|Encrypt" app/src/stores/settingStore.ts
echo -e "\n=== Full settingStore file ==="
cat app/src/stores/settingStore.tsLength of output: 4452
🏁 Script executed:
#!/bin/bash
# Verify if any other security measures are applied to address storage
echo "=== Checking usage of getOrGeneratePointsAddress ==="
rg -n "getOrGeneratePointsAddress" --type=ts --type=js -B 2 -A 2
echo -e "\n=== Checking if pointsAddress is used on-chain ==="
rg -n "pointsAddress" --type=ts --type=js -B 1 -A 1 | head -50Length of output: 1498
Add getOrGeneratePointsAddress to IAuthContext interface and either encrypt pointsAddress storage or regenerate on-demand.
Two issues need resolution:
-
Export inconsistency (line 337):
getOrGeneratePointsAddressis publicly exported but missing fromIAuthContextinterface (lines 204-215). Either add it to the interface as a public API method or prefix with underscore if intended as internal-only. -
Plaintext address storage (line 357): The derived address is persisted to AsyncStorage via
useSettingStore.setPointsAddress()without encryption, contradicting the store's own guidance: "Dont store anything sensative here" (settingStore.ts comment). While biometric auth protects the mnemonic derivation, the resulting address remains unencrypted and extractable from device backups. If on-chain activity privacy is a concern, either: encrypt before storage, regenerate on-demand from the keychain-protected mnemonic, or document this as an accepted tradeoff.
| address identityVerificationHubV2Address, | ||
| string memory scopeSeed | ||
| ) internal onlyInitializing { | ||
| SelfVerificationRootStorage storage $ = _getSelfVerificationRootStorage(); | ||
|
|
||
| $._identityVerificationHubV2 = IIdentityVerificationHubV2(identityVerificationHubV2Address); | ||
| $._scope = _calculateScope(address(this), scopeSeed, _getPoseidonAddress()); | ||
| } |
There was a problem hiding this comment.
Block invalid hub addresses during initialization.
Line 112: __SelfVerificationRoot_init accepts any address, so a rushed or adversarial initializer can set the hub to address(0) or an EOA. That permanently bricks verifySelfProof (every call reverts) or hands control to an attacker-controlled proxy that can spoof onVerificationSuccess. Reject zero addresses and require deployed bytecode before storing the hub reference. Solidity 0.8.28 exposes address.code.length, so you can enforce this without extra helpers.(docs.soliditylang.org)
Apply this diff to harden the initializer:
@@
- error InvalidDataFormat();
+ error InvalidDataFormat();
+
+ /// @notice Error thrown when the hub address is invalid
+ error InvalidHubAddress();
@@
function __SelfVerificationRoot_init(
address identityVerificationHubV2Address,
string memory scopeSeed
) internal onlyInitializing {
SelfVerificationRootStorage storage $ = _getSelfVerificationRootStorage();
+ if (identityVerificationHubV2Address == address(0) || identityVerificationHubV2Address.code.length == 0) {
+ revert InvalidHubAddress();
+ }
+
$._identityVerificationHubV2 = IIdentityVerificationHubV2(identityVerificationHubV2Address);
$._scope = _calculateScope(address(this), scopeSeed, _getPoseidonAddress());
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In contracts/contracts/abstract/SelfVerificationRootUpgradeable.sol around lines
107 to 114, the initializer currently accepts any address for
identityVerificationHubV2Address which can be zero or an EOA; add validation
before storing the reference: require(identityVerificationHubV2Address !=
address(0), "Invalid hub: zero address") and
require(identityVerificationHubV2Address.code.length > 0, "Invalid hub: no
contract code") so only deployed contracts are accepted, then proceed to cast
and store the IIdentityVerificationHubV2 reference and compute the scope as
before.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
| mapping(uint256 nullifier => uint256 userIdentifier) internal _nullifierToUserIdentifier; | ||
| mapping(uint256 userIdentifier => bool registered) internal _registeredUserIdentifiers; | ||
|
|
||
| event Claimed(uint256 index, address account, uint256 amount); | ||
| event RegistrationOpen(); | ||
| event RegistrationClose(); | ||
| event ClaimOpen(); | ||
| event ClaimClose(); | ||
| event UserIdentifierRegistered(uint256 indexed registeredUserIdentifier, uint256 indexed nullifier); | ||
| event MerkleRootUpdated(bytes32 newMerkleRoot); | ||
|
|
||
| error InvalidProof(); | ||
| error AlreadyClaimed(); | ||
| error NotRegistered(address nonRegisteredAddress); | ||
| error RegistrationNotOpen(); | ||
| error RegistrationNotClosed(); | ||
| error ClaimNotOpen(); | ||
| error InvalidUserIdentifier(); | ||
| error UserIdentifierAlreadyRegistered(); | ||
| error RegisteredNullifier(); | ||
|
|
||
| constructor( | ||
| address identityVerificationHubAddress, | ||
| string memory scopeSeed, | ||
| address tokenAddress | ||
| ) TestSelfVerificationRoot(identityVerificationHubAddress, scopeSeed) Ownable(_msgSender()) { | ||
| token = IERC20(tokenAddress); | ||
| } | ||
|
|
||
| function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner { | ||
| merkleRoot = newMerkleRoot; | ||
| emit MerkleRootUpdated(newMerkleRoot); | ||
| } | ||
|
|
||
| function openRegistration() external onlyOwner { | ||
| isRegistrationOpen = true; | ||
| emit RegistrationOpen(); | ||
| } | ||
|
|
||
| function closeRegistration() external onlyOwner { | ||
| isRegistrationOpen = false; | ||
| emit RegistrationClose(); | ||
| } | ||
|
|
||
| function openClaim() external onlyOwner { | ||
| isClaimOpen = true; | ||
| emit ClaimOpen(); | ||
| } | ||
|
|
||
| function closeClaim() external onlyOwner { | ||
| isClaimOpen = false; | ||
| emit ClaimClose(); | ||
| } | ||
|
|
||
| function isRegistered(address registeredAddress) external view returns (bool) { | ||
| return _registeredUserIdentifiers[uint256(uint160(registeredAddress))]; | ||
| } | ||
|
|
||
| function setConfigId(bytes32 configId) external override onlyOwner { | ||
| verificationConfigId = configId; | ||
| } | ||
|
|
||
| function claim(uint256 index, uint256 amount, bytes32[] memory merkleProof) external { | ||
| if (isRegistrationOpen) revert RegistrationNotClosed(); | ||
| if (!isClaimOpen) revert ClaimNotOpen(); | ||
| if (claimed[msg.sender]) revert AlreadyClaimed(); | ||
| if (!_registeredUserIdentifiers[uint256(uint160(msg.sender))]) revert NotRegistered(msg.sender); | ||
|
|
||
| bytes32 node = keccak256(abi.encodePacked(index, msg.sender, amount)); | ||
| if (!MerkleProof.verify(merkleProof, merkleRoot, node)) revert InvalidProof(); | ||
|
|
||
| claimed[msg.sender] = true; | ||
| token.safeTransfer(msg.sender, amount); | ||
| emit Claimed(index, msg.sender, amount); | ||
| } | ||
|
|
||
| function customVerificationHook( | ||
| ISelfVerificationRoot.GenericDiscloseOutputV2 memory output, | ||
| bytes memory /* userData */ | ||
| ) internal override { | ||
| if (!isRegistrationOpen) revert RegistrationNotOpen(); | ||
| if (_nullifierToUserIdentifier[output.nullifier] != 0) revert RegisteredNullifier(); | ||
| if (output.userIdentifier == 0) revert InvalidUserIdentifier(); | ||
| if (_registeredUserIdentifiers[output.userIdentifier]) revert UserIdentifierAlreadyRegistered(); | ||
|
|
||
| _nullifierToUserIdentifier[output.nullifier] = output.userIdentifier; | ||
| _registeredUserIdentifiers[output.userIdentifier] = true; | ||
|
|
||
| emit UserIdentifierRegistered(output.userIdentifier, output.nullifier); |
There was a problem hiding this comment.
Registered users can never claim
customVerificationHook registers users under output.userIdentifier, but claim checks _registeredUserIdentifiers[uint256(uint160(msg.sender))]. Those keys never match (userIdentifier is a hash, not the raw address), so every claim reverts with NotRegistered. We need to persist registration by address (or otherwise bridge the mapping) when verifying.
- mapping(uint256 userIdentifier => bool registered) internal _registeredUserIdentifiers;
+ mapping(uint256 userIdentifier => bool registered) internal _registeredUserIdentifiers;
+ mapping(address account => bool registered) internal _registeredAccounts;
@@
- function isRegistered(address registeredAddress) external view returns (bool) {
- return _registeredUserIdentifiers[uint256(uint160(registeredAddress))];
+ function isRegistered(address registeredAddress) external view returns (bool) {
+ return _registeredAccounts[registeredAddress];
@@
- if (_registeredUserIdentifiers[uint256(uint160(msg.sender))]) revert NotRegistered(msg.sender);
+ if (!_registeredAccounts[msg.sender]) revert NotRegistered(msg.sender);
@@
- _registeredUserIdentifiers[output.userIdentifier] = true;
+ _registeredUserIdentifiers[output.userIdentifier] = true;
+ _registeredAccounts[msg.sender] = true;There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
| // Use a dummy private key for CI/local development (not used for actual deployments) | ||
| const DUMMY_PRIVATE_KEY = "0x0000000000000000000000000000000000000000000000000000000000000001"; | ||
| const PRIVATE_KEY = process.env.PRIVATE_KEY || DUMMY_PRIVATE_KEY; |
There was a problem hiding this comment.
CRITICAL: Fallback to dummy private key creates deployment risk.
The current implementation silently falls back to a publicly known dummy key when PRIVATE_KEY is not set. This creates serious risks:
- Production deployment failure: If the environment variable is misconfigured, deployments will use the dummy key without warning
- Fund loss: The dummy key address is publicly known—any funds sent during deployment could be intercepted
- Silent failure: No validation warns operators that the dummy key is being used
Apply this diff to fail fast when the private key is missing:
-// Use a dummy private key for CI/local development (not used for actual deployments)
-const DUMMY_PRIVATE_KEY = "0x0000000000000000000000000000000000000000000000000000000000000001";
-const PRIVATE_KEY = process.env.PRIVATE_KEY || DUMMY_PRIVATE_KEY;
+const PRIVATE_KEY = process.env.PRIVATE_KEY;
+
+if (!PRIVATE_KEY) {
+ throw new Error("PRIVATE_KEY environment variable is required for network deployments");
+}For CI/local development that doesn't require deployments, configure Hardhat to skip network account validation or use the built-in hardhat network with test mnemonics.
📝 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.
| // Use a dummy private key for CI/local development (not used for actual deployments) | |
| const DUMMY_PRIVATE_KEY = "0x0000000000000000000000000000000000000000000000000000000000000001"; | |
| const PRIVATE_KEY = process.env.PRIVATE_KEY || DUMMY_PRIVATE_KEY; | |
| const PRIVATE_KEY = process.env.PRIVATE_KEY; | |
| if (!PRIVATE_KEY) { | |
| throw new Error("PRIVATE_KEY environment variable is required for network deployments"); | |
| } |
🤖 Prompt for AI Agents
In contracts/hardhat.config.ts around lines 11-13, remove the unconditional
fallback to the public dummy private key and enforce fail-fast behavior: require
process.env.PRIVATE_KEY and if missing throw an error (or process.exit(1)) with
a clear message instructing to set PRIVATE_KEY or enable a deliberate
non-production flag; alternatively allow an explicit opt-in (e.g.,
ALLOW_DUMMY_KEY=true) for local/CI only, and document using the built-in hardhat
network or test mnemonics for CI instead of providing a dummy key.
| #ifndef HEADER_IDEA_H | ||
| # define HEADER_IDEA_H | ||
|
|
||
| # include <openssl/opensslconf.h> |
There was a problem hiding this comment.
Blocker: missing opensslconf.h stops the build.
The compile step fails because <openssl/opensslconf.h> is not present in the XCFramework include set (clang reports 'openssl/opensslconf.h' file not found). We either need to ship that header in Headers/openssl/opensslconf.h or adjust the include to an existing location; otherwise any consumer including idea.h will fail to build.
🧰 Tools
🪛 Clang (14.0.6)
[error] 13-13: 'openssl/opensslconf.h' file not found
(clang-diagnostic-error)
🤖 Prompt for AI Agents
packages/mobile-sdk-alpha/ios/Frameworks/OpenSSL.xcframework/ios-arm64_x86_64-maccatalyst/OpenSSL.framework/Headers/idea.h
(line 13): the current include uses <openssl/opensslconf.h> which is not present
in the XCFramework and breaks consumer builds; fix by either adding the missing
header into the framework include tree at Headers/openssl/opensslconf.h
(ensuring it’s packaged in the .xcframework and exported in the framework header
map/umbrella) or change the include to a path that exists inside the framework
(for example include "opensslconf.h" or the correct relative path) and update
the framework header exports and podspec/packaging so clang can resolve it;
after change, rebuild the XCFramework and verify a simple consumer target can
include idea.h without errors.
| # include <openssl/kdferr.h> | ||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| # define EVP_PKEY_CTRL_TLS_MD (EVP_PKEY_ALG_CTRL) | ||
| # define EVP_PKEY_CTRL_TLS_SECRET (EVP_PKEY_ALG_CTRL + 1) | ||
| # define EVP_PKEY_CTRL_TLS_SEED (EVP_PKEY_ALG_CTRL + 2) | ||
| # define EVP_PKEY_CTRL_HKDF_MD (EVP_PKEY_ALG_CTRL + 3) | ||
| # define EVP_PKEY_CTRL_HKDF_SALT (EVP_PKEY_ALG_CTRL + 4) | ||
| # define EVP_PKEY_CTRL_HKDF_KEY (EVP_PKEY_ALG_CTRL + 5) | ||
| # define EVP_PKEY_CTRL_HKDF_INFO (EVP_PKEY_ALG_CTRL + 6) | ||
| # define EVP_PKEY_CTRL_HKDF_MODE (EVP_PKEY_ALG_CTRL + 7) | ||
| # define EVP_PKEY_CTRL_PASS (EVP_PKEY_ALG_CTRL + 8) | ||
| # define EVP_PKEY_CTRL_SCRYPT_SALT (EVP_PKEY_ALG_CTRL + 9) | ||
| # define EVP_PKEY_CTRL_SCRYPT_N (EVP_PKEY_ALG_CTRL + 10) | ||
| # define EVP_PKEY_CTRL_SCRYPT_R (EVP_PKEY_ALG_CTRL + 11) | ||
| # define EVP_PKEY_CTRL_SCRYPT_P (EVP_PKEY_ALG_CTRL + 12) | ||
| # define EVP_PKEY_CTRL_SCRYPT_MAXMEM_BYTES (EVP_PKEY_ALG_CTRL + 13) |
There was a problem hiding this comment.
Ship kdferr.h with this drop or the build breaks.
kdf.h still depends on <openssl/kdferr.h>, but that header is absent from the xcframework (clang already fails with “‘openssl/kdferr.h’ file not found”). Until you package that dependency alongside kdf.h (or adjust the include to a header you do ship), anything touching HKDF/TLS PRF will fail to compile. Please add the missing header before promoting to staging.
🧰 Tools
🪛 Clang (14.0.6)
[error] 13-13: 'openssl/kdferr.h' file not found
(clang-diagnostic-error)
🤖 Prompt for AI Agents
In
packages/mobile-sdk-alpha/ios/Frameworks/OpenSSL.xcframework/ios-arm64_x86_64-maccatalyst/OpenSSL.framework/Headers/kdf.h
around lines 13 to 31, kdf.h includes <openssl/kdferr.h> which is not present in
the xcframework causing clang “‘openssl/kdferr.h’ file not found”; fix by either
adding and shipping the missing kdferr.h into the Frameworks/.../Headers
directory (and update the xcframework packaging manifest to include it) or
change the include to an existing header you do ship and update any
symbol/constant definitions accordingly; after adding or changing the include,
rebuild the xcframework and verify compilation of HKDF/TLS PRF-related sources.
| # ifndef HEADER_SYMHACKS_H | ||
| # include <openssl/symhacks.h> | ||
| # endif |
There was a problem hiding this comment.
Ship openssl/symhacks.h alongside this header.
Line 15 pulls in <openssl/symhacks.h>, but the xcframework doesn’t ship that header (Clang already emits 'openssl/symhacks.h' file not found). Any consumer that imports kdferr.h will fail to compile. Please bundle the rest of the openssl/ header tree (keeping the directory structure) or adjust the include to point at the location you actually deliver. Until that happens this header is unusable.
🧰 Tools
🪛 Clang (14.0.6)
[error] 15-15: 'openssl/symhacks.h' file not found
(clang-diagnostic-error)
🤖 Prompt for AI Agents
In
packages/mobile-sdk-alpha/ios/Frameworks/OpenSSL.xcframework/ios-arm64_x86_64-maccatalyst/OpenSSL.framework/Headers/kdferr.h
around lines 14–16, the file includes <openssl/symhacks.h> but that header is
not shipped, causing compilation failures; fix by either bundling the missing
openssl/ header tree (include symhacks.h in the
OpenSSL.framework/Headers/openssl/ path so the include <openssl/symhacks.h>
resolves) or change the include to the actual shipped relative path (e.g., use a
local header location and update header search paths and the xcframework header
layout accordingly); ensure the directory structure is preserved or the include
path and framework headers map are updated so consumers can compile.
| # include <openssl/e_os2.h> | ||
| # include <openssl/bio.h> | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| typedef struct lhash_node_st OPENSSL_LH_NODE; | ||
| typedef int (*OPENSSL_LH_COMPFUNC) (const void *, const void *); | ||
| typedef unsigned long (*OPENSSL_LH_HASHFUNC) (const void *); | ||
| typedef void (*OPENSSL_LH_DOALL_FUNC) (void *); | ||
| typedef void (*OPENSSL_LH_DOALL_FUNCARG) (void *, void *); |
There was a problem hiding this comment.
Respect the openssl/ folder structure when exporting headers.
lhash.h includes <openssl/e_os2.h> (Line 18), but in this xcframework e_os2.h lives at the top level. Because the openssl/ directory isn’t present, consumers hit 'openssl/e_os2.h' file not found. Please move the headers under Headers/openssl/ (or supply a header map/module map that mirrors the expected layout) so the standard OpenSSL include paths resolve.
🧰 Tools
🪛 Clang (14.0.6)
[error] 17-17: 'openssl/e_os2.h' file not found
(clang-diagnostic-error)
🤖 Prompt for AI Agents
packages/mobile-sdk-alpha/ios/Frameworks/OpenSSL.xcframework/ios-arm64_x86_64-maccatalyst/OpenSSL.framework/Headers/lhash.h
lines 17-28: lhash.h includes <openssl/e_os2.h> but the xcframework exposes
headers at top-level, causing 'openssl/e_os2.h' not found; fix by reorganizing
the framework Headers to preserve OpenSSL's expected include path (move e_os2.h
and other OpenSSL headers into Headers/openssl/ so the header hierarchy matches
#include "openssl/..." usage) or alternatively add a header map/module map in
the framework that maps openssl/* to the current top-level headers and update
the framework's umbrella/module map accordingly so consumers can #include
<openssl/e_os2.h> without errors.
| #include <OpenSSL/ssl.h> | ||
|
|
||
| #include <OpenSSL/ssl2.h> | ||
| #include <OpenSSL/ssl3.h> | ||
| #include <OpenSSL/sslerr.h> | ||
|
|
||
| #include <OpenSSL/aes.h> | ||
| #include <OpenSSL/asn1.h> | ||
| #include <OpenSSL/asn1err.h> | ||
| #include <OpenSSL/asn1t.h> | ||
| #include <OpenSSL/async.h> | ||
| #include <OpenSSL/asyncerr.h> | ||
| #include <OpenSSL/bio.h> | ||
| #include <OpenSSL/bioerr.h> | ||
| #include <OpenSSL/blowfish.h> | ||
| #include <OpenSSL/bn.h> | ||
| #include <OpenSSL/bnerr.h> | ||
| #include <OpenSSL/buffer.h> | ||
| #include <OpenSSL/buffererr.h> | ||
| #include <OpenSSL/camellia.h> | ||
| #include <OpenSSL/cast.h> | ||
| #include <OpenSSL/cmac.h> | ||
| #include <OpenSSL/cms.h> | ||
| #include <OpenSSL/cmserr.h> | ||
| #include <OpenSSL/comp.h> | ||
| #include <OpenSSL/comperr.h> | ||
| #include <OpenSSL/conf.h> | ||
| #include <OpenSSL/conf_api.h> | ||
| #include <OpenSSL/conferr.h> | ||
| #include <OpenSSL/crypto.h> | ||
| #include <OpenSSL/cryptoerr.h> | ||
| #include <OpenSSL/ct.h> | ||
| #include <OpenSSL/cterr.h> | ||
| #include <OpenSSL/des.h> | ||
| #include <OpenSSL/dh.h> | ||
| #include <OpenSSL/dherr.h> | ||
| #include <OpenSSL/dsa.h> | ||
| #include <OpenSSL/dsaerr.h> | ||
| #include <OpenSSL/dtls1.h> | ||
| #include <OpenSSL/e_os2.h> | ||
| #include <OpenSSL/ebcdic.h> | ||
| #include <OpenSSL/ec.h> | ||
| #include <OpenSSL/ecdh.h> | ||
| #include <OpenSSL/ecdsa.h> | ||
| #include <OpenSSL/ecerr.h> | ||
| #include <OpenSSL/engine.h> | ||
| #include <OpenSSL/engineerr.h> | ||
| #include <OpenSSL/err.h> | ||
| #include <OpenSSL/evp.h> | ||
| #include <OpenSSL/evperr.h> | ||
| #include <OpenSSL/hmac.h> | ||
| #include <OpenSSL/idea.h> | ||
| #include <OpenSSL/kdf.h> | ||
| #include <OpenSSL/kdferr.h> | ||
| #include <OpenSSL/lhash.h> | ||
| #include <OpenSSL/md2.h> | ||
| #include <OpenSSL/md4.h> | ||
| #include <OpenSSL/md5.h> | ||
| #include <OpenSSL/mdc2.h> | ||
| #include <OpenSSL/modes.h> | ||
| #include <OpenSSL/obj_mac.h> | ||
| #include <OpenSSL/objects.h> | ||
| #include <OpenSSL/objectserr.h> | ||
| #include <OpenSSL/ocsp.h> | ||
| #include <OpenSSL/ocsperr.h> | ||
| // #include <OpenSSL/opensslconf-arm64.h> | ||
| // #include <OpenSSL/opensslconf-arm64e.h> | ||
| // #include <OpenSSL/opensslconf-armv7.h> | ||
| // #include <OpenSSL/opensslconf-armv7s.h> | ||
| #include <OpenSSL/opensslconf.h> | ||
| #include <OpenSSL/opensslv.h> | ||
| #include <OpenSSL/ossl_typ.h> | ||
| #include <OpenSSL/pem.h> | ||
| #include <OpenSSL/pem2.h> | ||
| #include <OpenSSL/pemerr.h> | ||
| #include <OpenSSL/pkcs12.h> | ||
| #include <OpenSSL/pkcs12err.h> | ||
| #include <OpenSSL/pkcs7.h> | ||
| #include <OpenSSL/pkcs7err.h> | ||
| #include <OpenSSL/rand.h> | ||
| #include <OpenSSL/rand_drbg.h> | ||
| #include <OpenSSL/randerr.h> | ||
| #include <OpenSSL/rc2.h> | ||
| #include <OpenSSL/rc4.h> | ||
| #include <OpenSSL/rc5.h> | ||
| #include <OpenSSL/ripemd.h> | ||
| #include <OpenSSL/rsa.h> | ||
| #include <OpenSSL/rsaerr.h> | ||
| #include <OpenSSL/safestack.h> | ||
| #include <OpenSSL/seed.h> | ||
| #include <OpenSSL/sha.h> | ||
| #include <OpenSSL/shim.h> | ||
| #include <OpenSSL/srp.h> | ||
| #include <OpenSSL/srtp.h> | ||
| #include <OpenSSL/stack.h> | ||
| #include <OpenSSL/store.h> | ||
| #include <OpenSSL/storeerr.h> | ||
| #include <OpenSSL/symhacks.h> | ||
| #include <OpenSSL/tls1.h> | ||
| #include <OpenSSL/ts.h> | ||
| #include <OpenSSL/tserr.h> | ||
| #include <OpenSSL/txt_db.h> | ||
| #include <OpenSSL/ui.h> | ||
| #include <OpenSSL/uierr.h> | ||
| #include <OpenSSL/whrlpool.h> | ||
| #include <OpenSSL/x509.h> | ||
| #include <OpenSSL/x509_vfy.h> | ||
| #include <OpenSSL/x509err.h> | ||
| #include <OpenSSL/x509v3.h> | ||
| #include <OpenSSL/x509v3err.h> No newline at end of file |
There was a problem hiding this comment.
Umbrella header can’t compile as-is.
Including <OpenSSL/ssl.h> (and the rest of this list) currently fails—clang reports 'OpenSSL/ssl.h' file not found. Until the xcframework exports a matching OpenSSL/ include root or header map, every consumer pulling in this umbrella header will break. Please wire up the header search paths before promoting this release.
🧰 Tools
🪛 Clang (14.0.6)
[error] 2-2: 'OpenSSL/ssl.h' file not found
(clang-diagnostic-error)
🤖 Prompt for AI Agents
In
packages/mobile-sdk-alpha/ios/Frameworks/OpenSSL.xcframework/ios-arm64_x86_64-maccatalyst/OpenSSL.framework/Headers/OpenSSL.h
lines 2-111, the umbrella header currently includes headers like <OpenSSL/ssl.h>
but consumers get "OpenSSL/ssl.h file not found"; fix by making the xcframework
actually export an OpenSSL/ include root or adjusting the umbrella to match
exported layout: (a) ensure the framework's Headers directory (or an exported
header map) contains an OpenSSL/ subfolder with all public headers (or create a
header symlink/copy), (b) add the include path to the framework's public header
search paths/exported header map (or update module.modulemap to point to the
real header locations), and (c) rebuild the xcframework so the umbrella header
resolves when the framework is integrated.
🚀 Weekly Release to Staging
Release Date: November 01, 2025
Release Branch:
release/staging-2025-11-01This automated PR promotes a snapshot of
devtostagingfor testing.What's Included
All commits merged to
devup to the branch creation time.Note: This PR uses a dedicated release branch, so new commits to
devwill NOT automatically appear here.Review Checklist
Next Steps
After merging, the staging environment will be updated. A production release PR will be created on Sunday.
This PR was automatically created by the Release Calendar workflow on November 01, 2025
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Documentation
Chores