Martin/zkpassport demo - #8059
Conversation
Integrates the ZKPassportAttest registry into the Launches flow: - Creator wizard: a 'Use ZKPassport' option sources the policy dropdown from on-chain PolicyCreated logs and links out for custom policies. - Auction page: a Verify button opens the ZKPassport popup with the policyId read from the auction's validation hook, and eligibility refreshes from the popup's postMessage result without a reload. - Popup and policy-creator URLs are env-overridable (ZKPASSPORT_POPUP_URL, ZKPASSPORT_CREATE_POLICY_URL) with localhost fallbacks for dev. Also carries the workspace unblocks the build needs on a fresh checkout: nx.json/bun.lock updates and tsconfig/package stubs for workspace projects absent from this fork. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ9i1sp3EJA9wwPAViJS7X
On push to this branch, GitHub Actions builds the Vercel bundle (SKIP_CONFIG_PULL with a generated .env.override), injects an edge middleware that gates the whole SPA and /api proxy behind BASIC_AUTH_CREDENTIALS from the Vercel project env, and ships it with vercel deploy --prebuilt. Requires repo secrets VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID and repo variables ZKPASSPORT_POPUP_URL, ZKPASSPORT_CREATE_POLICY_URL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ9i1sp3EJA9wwPAViJS7X
The client picks proxy-vs-direct gateway URLs from config.enableEntryGatewayProxy, which is baked from the resolved .env files at build time — a shell env var alone never reaches the bundle. Uniswap's own Vercel builds get it from the pulled staging config, which this workflow skips, so the deployed bundle called entry-gateway.backend-staging directly and CORS blocked every /rpc/<chainId> call (auction data, ZKPassport policy log scans). Baking ENABLE_ENTRY_GATEWAY_PROXY into the generated .env.override routes those calls through the same-origin Hono proxy instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ9i1sp3EJA9wwPAViJS7X
Third-party deployments of this interface cannot reach the liquidity backend (no CORS), which only serves as a calldata builder for bids — the bidder's wallet signs and sends the transaction either way. Behind ZKPASSPORT_ONCHAIN_BIDS (baked at build; the deploy workflow enables it), submitBid calldata is encoded locally against the CCA auction contract, whose bidding is documented as a permissionless direct call. The encoder is pinned by a test reproducing a real sepolia bid's backend-built calldata byte for byte. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ9i1sp3EJA9wwPAViJS7X
Behind ZKPASSPORT_ONCHAIN_LAUNCH (baked at build; the deploy workflow enables it), auction creation maps the wizard's existing request onto Uniswap's public @uniswap/liquidity-launcher-sdk instead of the CORS-blocked liquidity backend — the SDK assembles the same launcher multicall the backend builds, verified byte-for-byte against a real sepolia launch transaction. Scope matches the demo: new tokens with an optional validation hook; existing-token launches and liquidity locks throw a descriptive error through the existing failure surface. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ9i1sp3EJA9wwPAViJS7X
The web app routes every chain read through UniRPC (/entry-gateway/rpc/<chainId>), which 401s until a gateway session is established. Viewers without one (fresh profile, failed Turnstile challenge on a third-party domain) still see the auction page — its data rides sessionless connect endpoints — but the zk hook introspection fails, isGated stays false, and the bid form shows a spurious "Auction not supported" banner. Move the gate's reads (hook erc1155()/tokenId(), registry balanceOf) to a public client built from the chain's Default/Fallback RPC URLs, which need neither a session nor an API key. Also stop the backend verify-wallet outcome from disabling the bid button on zk-gated auctions: the hook validates on-chain, and VerifyWallet rides the CORS-blocked liquidity backend on third-party origins. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ9i1sp3EJA9wwPAViJS7X
The mobile app rejects proofs whose claimed domain differs from the popup's actual origin, and the registry domain is constructor-fixed, so a second registry was deployed with the popup's real host (zkpassport-attest-popup.vercel.app) as its domain. Make the registry address and deploy block overridable via ZKPASSPORT_ATTEST_REGISTRY_SEPOLIA / ZKPASSPORT_ATTEST_DEPLOY_BLOCK_SEPOLIA repo variables so future rewires only need a workflow re-run, not a commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ9i1sp3EJA9wwPAViJS7X
The launch success screen navigated to the build-time CREATE2 prediction, which can diverge from the deployed address: the LBP strategy derives its own factory salt and patches the auction params before create, so replaying factory.getAddress client-side does not always hash to the same address (observed on sepolia: predicted 0x46dA7929… vs deployed 0x44284947…). Resolve the deployed address from the AuctionCreated log in the launch receipt over the sessionless client, keeping the prediction as the fallback when the receipt cannot be fetched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ9i1sp3EJA9wwPAViJS7X
The bid review modal simulates every bid against the liquidity backend's SubmitBid before submitting, which is CORS-blocked from third-party origins — so the review flow stalled before ever reaching the wallet. With ZKPASSPORT_ONCHAIN_BIDS the calldata is encoded locally, the CCA contract enforces price validity, and the wallet's gas estimation surfaces reverts before signing, so the dry-run adds nothing there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ9i1sp3EJA9wwPAViJS7X
| with: | ||
| node-version-file: .nvmrc | ||
|
|
||
| - uses: oven-sh/setup-bun@v2 |
There was a problem hiding this comment.
Semgrep identified an issue in your code:
An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload. Github, foundry, and uniswap made github actions are exempt.
To resolve this comment:
✨ Commit fix suggestion
| - uses: oven-sh/setup-bun@v2 | |
| - uses: oven-sh/setup-bun@<VERIFIED_VALUE_REQUIRED> # v2 | |
| with: | |
| bun-version: 1.3.14 |
View step-by-step instructions
- Identify the trusted commit SHA for the
v2release ofoven-sh/setup-bunfrom its official repository or release tag. - Replace the mutable tag with the full 40-character commit SHA and keep the release as a comment for readability:
- uses: oven-sh/setup-bun@<40-character-commit-sha> # v2 - Keep
bun-version: 1.3.14unchanged so the workflow continues to install the intended Bun version.
💬 Ignore this finding
Reply with Semgrep commands to ignore this finding.
/fp <comment>for false positive/ar <comment>for acceptable risk/other <comment>for all other reasons
Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by third-party-action-not-pinned-to-commit-sha-foundry-allowed.
You can view more details about this finding in the Semgrep AppSec Platform.
The popup page opens with full browser chrome (no window features), and the attest request no longer sends walletAddress: the recipient account is connected and selected inside the popup, which reports it back in the outcome. The gate still checks the wallet connected here, so it unlocks only when the chosen account matches. Claude-Session: https://claude.ai/code/session_01AgsZAYrEuYPXZqhZ5Ahajr
No description provided.