Conversation
Replace all REACT_APP_* environment variables with OPENSCAN_* prefix and use import.meta.env instead of process.env for runtime access. Add envPrefix: "OPENSCAN_" to Vite config so OPENSCAN_* vars are auto-exposed without manual define entries. Only computed defaults (COMMIT_HASH, VERSION, ENVIRONMENT) remain in the define map. Closes #347
Add entry-deno.ts that sources env vars from Deno.env and passes them to the shared Hono app via app.fetch(request, env). All existing route handlers and middleware work unchanged. Add deno.json with sloppy-imports for Node-style resolution and npm import maps for the hono dependency. Ref #339
Add api/index.ts that sources env vars from process.env and passes them to the shared Hono app via app.fetch(request, env). All existing route handlers and middleware work unchanged. Add vercel.json with a catch-all rewrite to route all paths to the edge function handler. Ref #339
Add fetchWithWorkerFailover() that tries each worker URL in order (Cloudflare → Deno Deploy → Vercel) and falls through on network errors, 429, 502, and 503 responses. Update all direct worker proxy consumers (contractLookup, useEtherscan, AIService) to use the failover function. Update isWorkerProxyUrl to check against all worker URLs. Closes #339
The worker tsconfig only includes @cloudflare/workers-types, so process.env is unknown. Declare it locally instead of adding @types/node.
Document the worker proxy architecture, routes, environment variables, and step-by-step deployment instructions for Cloudflare Workers, Deno Deploy, and Vercel Edge Functions.
Deno Deploy entry point and config remain available for future use but are not included in the active failover chain until deployment is configured. Failover is now Cloudflare → Vercel.
Adds Solana as a third network type alongside EVM and Bitcoin, with dashboard, slots/blocks, transactions, accounts, SPL tokens, and validators views.
Bumps @openscan/network-connectors to 1.7 (which now ships SolanaClient), deletes the local SolanaClientTypes stub, replaces the inline JSON-RPC client in DataService with ClientFactory.createTypedClient, and updates SolanaAdapter and adaptersFactory to use the real types.
…kIndicator - Add public Solana RPC endpoints (mainnet-beta, devnet, testnet) to BUILTIN_RPC_DEFAULTS so the app can connect out of the box - Add Solana branch to NetworkBlockIndicator so the navbar shows the current slot for Solana networks instead of crashing with "At least one RPC URL must be provided"
Adds PublicNode, dRPC, Ankr, and Pocket Network as additional fallback RPCs for Solana mainnet, devnet, and testnet so the fallback strategy has more options when the official endpoints are rate-limited.
Refactors all Solana pages to use the same shared style classes and patterns established by the Bitcoin/EVM pages: - Wrap pages in container-wide / page-container-padded - Use Breadcrumb on every detail and list page - Use block-display-card, blocks-header, block-display-header, block-label, tx-details, tx-row, tx-value, tx-mono, tx-link - Use dash-table / table-wrapper / table-cell-* classes for tables - Use block-status-badge for status indicators - Use LoaderWithTimeout for loading states - Add CopyButton to addresses, signatures, mints, blockhashes - Skeleton placeholders match the Bitcoin loading pattern New display components extracted (mirroring BitcoinBlockDisplay pattern): - SolanaSlotDisplay - SolanaTransactionDisplay - SolanaAccountDisplay
- SolanaTransactionsPage and SolanaAccountDisplay now use the shared table-status-badge / table-status-success / table-status-failed classes (matching EVM TransactionHistory) so the success/failed pills render with rounded corners. - Add a block-status-failed CSS rule next to block-status-finalized and block-status-pending so the SolanaTransactionDisplay header badge has the correct red rounded style.
…ldings Wrap the account details and token holdings inside btc-tx-details-grid so they render side-by-side, mirroring the BTC/EVM address page layout. The address row stays full-width on top, then the left column holds the account metadata (balance, owner, executable, data size, rent) and the right column holds the SPL token holdings table.
…s as section header - Move the address row into its own tx-details block outside the two-column grid so it spans the full card width. - Replace the 'Token Holdings:' tx-row label with a proper block-display-section-title header inside the right column, so the token table has its own section heading like the rest of the app.
The custom tx-link class doesn't exist — replace all occurrences in SolanaTransactionDisplay, SolanaSlotDisplay, and SolanaAccountDisplay with link-accent tx-mono, matching how BTC/EVM detail pages render their block/slot/account/tx links.
Replace the Transactions stat card (which showed the cumulative transaction count) with a Version stat card. The cumulative count isn't useful at a glance and was taking up a prominent dashboard slot.
Remove the Version stat card so the Solana dashboard header only shows SOL Price, Current Slot, and Epoch.
Replace the table-based collapsible transactions section in SolanaSlotDisplay with the tx-list / tx-list-item / tx-list-index / tx-list-hash pattern used by EVM BlockAnalyser and BTC BitcoinBlockDisplay, toggled via a more-details-toggle button. The signatures now render as a numbered list of full hashes with link-accent styling, matching how EVM and BTC blocks display their transaction lists.
…te-prefix refactor: migrate REACT_APP_ env vars to OPENSCAN_ prefix
Replace the bare <pre> with nonexistent log-output class with the shared more-details-toggle / more-details-content / detail-row pattern. Logs now render as a numbered list inside the styled container, matching how EVM raw traces and block details display expandable content.
Merge dev into feat/worker-multi-platform-deploy and resolve the workerConfig.ts conflict. The primary worker URL now reads from import.meta.env.OPENSCAN_WORKER_URL (matching the REACT_APP_ → Vite env migration already on dev) while keeping the failover array and fetchWithWorkerFailover logic from this branch.
- Add 15s AbortController timeout per request so a hanging worker doesn't block the entire failover chain - On 429 (rate limited): wait Retry-After header (capped at 10s, default 3s) and retry once on the same worker before failing over - 502/503 still trigger immediate failover to the next worker - Extracted fetchWithTimeout helper for clean abort handling
Regenerate bun.lock to pass --frozen-lockfile check in CI. Add axios >=1.15.0 override to resolve critical SSRF/header injection vulnerabilities in transitive dependency from @coinbase/cdp-sdk.
feat(solana): add Solana network support (Mainnet, Devnet, Testnet)
…-multi-platform-deploy
feat: add redundant worker deployments on Deno Deploy and Vercel
|
🚀 Preview: https://pr-360--openscan.netlify.app |
The phase 3 smokes (avalanche, solana, testnets) plus phase 1's errors.spec.ts each redefined the same `expectStillMounted` helper with the same footer selector and timeout constants. Four copies of a six-line function is copy-paste drift waiting to happen. Move the helper and its `FOOTER_SELECTOR` constant to `e2e/fixtures/assertions.ts` and import it from each spec. One file to update when the footer selector rotates or the mount-verification strategy changes. No test behavior change; 363 tests discover identically.
Add three shallow specs that cover cross-network features the existing suite touches only incidentally: - `shared/contract-interaction.spec.ts` (3 tests): on USDC mainnet, assert the "Read Functions (N)" and "Write Functions (N)" section headers render. Neither submits a transaction (wallet signing is out of scope for e2e). Plus one smoke on a non-verified address to verify the page still renders without an ABI. Label regex sourced from `src/locales/en/address.json` (`readFunctionsCount` / `writeFunctionsCount`). - `shared/ai-and-worker.spec.ts` (2 tests): on a tx page, assert the `<section class="ai-analysis-panel">` renders and the `.ai-analysis- button` is enabled. We don't click Analyze — that would burn Groq budget and couple to live availability. Worker failover (Cloudflare 5xx → Vercel) remains in the `mocked/rpc-strategy.spec.ts` TODO. - `shared/large-tx.spec.ts` (1 test): on the USDC approval tx pinned in `e2e/fixtures/mainnet.ts`, assert `.tx-log` row renders in `EventLogsTab`. Baseline coverage for the log-decode path; stress against a 100+ log tx deferred to phase 6 once a stable fixture is curated. Full hermetic `shared/mocked/nft-safety.spec.ts` (regression test for the H-2 `toSafeExternalHref` fix) remains a skip-placeholder. A robust version requires mocking `tokenURI` + `name` + `symbol` + `ownerOf` eth_calls as well as the metadata JSON fetch, which is still heavier than the phase-4 budget. 363 → 369 tests runnable (+6 runnable, skips unchanged).
Self-review of 8dd0d9a: the third `contract-interaction.spec.ts` test claimed to cover "contract with code but no verified source" but used the zero address — which is an EOA with zero bytecode. The assertion passed trivially and it duplicated `${net.name} — zero address renders` already present in `errors.spec.ts`. Remove the test rather than paper over it; note in a comment that a real unverified-contract coverage case is a phase-6 item that requires picking a stably-unverified mainnet contract. 369 → 368 tests runnable.
Extend the CI matrix so every spec group added in phases 1–4 has a trigger, and add a nightly cron so live-RPC drift between PRs is caught without blocking merges. - `e2e-evm-networks.yml`: add `avalanche` shard (phase 3 Avalanche smoke) and `l2-fields` shard (phase 2 L2 adapter assertions) to the existing matrix. - `e2e-shared.yml` (new): cross-network matrix over errors, search, settings, contract-interaction, ai-and-worker, large-tx. Six parallel shards, same shape as the evm-networks workflow. Uses the explicit `--project=chromium` flag so CI never accidentally runs the deferred `mocked` project's placeholder skips. - `e2e-solana.yml` (new): single job for `e2e/tests/solana/`. Solana RPC is discovered via `@openscan/metadata` — no dedicated secret required. - `e2e-testnets.yml` (new): single job for `e2e/tests/testnets/`. Same metadata-driven RPC discovery; takes the optional INFURA / ALCHEMY secrets for mainnet-adjacent cross-chain calls (ENS resolution during search). - `e2e-all.yml`: thread the three new workflows into the orchestrator so manual "run everything" and the nightly both hit them. - `e2e-nightly.yml` (new): 06:00 UTC cron that calls `e2e-all.yml`. Explicit comment in the header noting it must not gate merges — nightly red ≠ PR red. Total CI coverage: 6 shards (up from 5) in evm-networks, 6 new shards in shared, 1 new job each for solana / testnets, 1 nightly orchestrator. Each per-PR workflow still triggers on `pull_request` → `main`, preserving the existing gate model.
Phase 4's review commit re-scoped the "large-tx" spec down to a single "at least one event log renders" assertion but left the filename as-is. The file no longer exercises large-tx pagination or virtualization — it just covers event-log decoding for a single-log tx. Rename for honesty and update the CI matrix entry in `e2e-shared.yml` to match. True "large tx" stress (100+ logs, virtualization) remains a phase-6 backlog item.
End of the refactor. No `.only` markers, no commented-out tests, no unjustified timeouts in any spec added across phases 0–5. Two documentation updates: - `README.md`: expand the E2E section to reflect the new `e2e/tests/` layout (eth-mainnet, evm-networks, bitcoin, solana, testnets, shared, shared/mocked), list what each area covers, and describe the PR-vs-nightly CI triggers. Also document the two Playwright projects (`chromium` live + `mocked` hermetic) for readers who wonder why some specs are excluded from the default project. - `.claude/rules/commands.md`: add the `--project=chromium` invocation as a documented recipe so future contributors know how to skip the hermetic suite when they don't need it. Backlog not closed in this refactor (explicit TODOs landed in the placeholder spec bodies): - `shared/mocked/nft-safety.spec.ts` — H-2 regression with full `tokenURI` + metadata fetch mocking. - `shared/mocked/rpc-strategy.spec.ts` — fallback / parallel / race strategy verification plus Cloudflare → Vercel worker failover. - `evm-networks/l2-fields.spec.ts` — blob field assertions (blobGasUsed / excessBlobGas) on post-Dencun blocks. - `solana/` deep field assertions (need a curated `solana.ts` fixture equivalent to `mainnet.ts`). - Large-tx stress (100+ logs) in `event-logs.spec.ts`. - Unverified-contract coverage in `contract-interaction.spec.ts`. Final test count: 281 → 369 discovered (~88 additions; roughly 77 runnable + ~11 skip-placeholders documenting deferred work).
Self-review: the README E2E section described what exists but gave no pointer for how to extend it. Contributors reading the file fresh would need to reverse-engineer from existing specs + CI workflows to figure out where a new spec belongs. Add a short 4-step "Adding a new spec" block covering the four common cases (new network / cross-network feature / chain-specific feature / hermetic test) and which file + workflow touch each requires. Keeps the change narrow to docs so it can't regress the code.
Running the refactor-scoped suite against a local dev server exposed
four bugs, all in specs added during phases 2–4. No application code
changes.
- `event-logs.spec.ts`: `TxAnalyser` starts collapsed for non-
super-users (`collapsed = !isSuperUser`). Clicking the "Events (N)"
tab is what expands the panel and mounts `.tx-log`. The original
spec skipped this step. Also switch the fixture tx from the 2022
USDC approval (block 15M, flaky on public RPCs) to the EIP-1559
tx at block 20M that's already pinned in `mainnet.ts`.
- `contract-interaction.spec.ts`: two bugs —
1. USDC is a proxy; `ContractInteraction.tsx` surfaces only the
proxy's tiny admin ABI, so "Write Functions" never renders.
Swap to WETH9 (verified, non-proxy, small stable ABI).
2. Contract Details is collapsed by default. The `openContractDetails`
helper now waits explicitly for the header element and then
clicks it — the previous `Balance: OR Contract Details` race
could resolve on `Balance:` before the header mounted, causing
the subsequent `isVisible` check to return false and the click
to be skipped.
- `l2-fields.spec.ts` / `assertionsL2.ts`:
1. Default Playwright 5s timeout was too short — L2 receipts via
public RPC can take 10–20s. Bump the helper timeout to
`DEFAULT_TIMEOUT * 4` across all L2 assertions.
2. The Arbitrum tx / block cases need an RPC that returns
Arbitrum's extended receipt shape (`l1BlockNumber`, `sendCount`,
`sendRoot`). Public endpoints strip these fields and the local
Alchemy/Infura used in testing doesn't expose them either.
Mark both as `test.fixme` with an explicit comment — to be
un-fixmed once a confirmed Arbitrum-native RPC is wired into
CI secrets and a conditional skip on that env var is added.
The OP/Base L1 fee specs pass (OP clean, Base flaky-on-retry).
Run result on my local dev server with the test's Alchemy/Infura seed:
75 passed, 5 skipped (2 new fixme + 3 blob placeholders), 0 failed in
57s. Typecheck clean.
None of these tests come from the e2e refactor — they've been failing
intermittently on the `dev` branch against public RPCs because of the
same two root causes surfaced by the full-suite run:
1. `.loader-container` doesn't exist on `/blocks` — the component
renders a skeleton table while loading (`src/components/pages/evm/
blocks/index.tsx:165`). `toBeHidden({ timeout })` on that locator
therefore passes instantly, leaving the subsequent assertions to
race real data loading under default 5s timeouts. Rewrite the wait
to anchor on `.blocks-header-main` — the element that mounts only
in the data branch — with an RPC-sized budget.
2. Click-then-assert races on pagination: clicking "Older" triggers a
navigate + RPC round-trip. The 5s default for "Newer becomes
enabled" isn't enough when public endpoints are rate-limited.
Replace with `page.waitForURL(/fromBlock=/)` as the navigation
signal, then `toBeEnabled({ timeout: DEFAULT_TIMEOUT * 3 })`.
Covered:
- `blocks.spec.ts:5` (header) — anchor on data-branch element.
- `blocks.spec.ts:53` (single-line header) — same.
- `blocks.spec.ts:114` (pagination) — waitForURL + longer enabled-wait.
- `txs.spec.ts:120` (tx pagination navigate-between) — same
multiplier-bump treatment applied to all pagination assertions.
- `arbitrum.spec.ts:250` (Uniswap V3 swap details) — Arbitrum public
RPCs are slower than mainnet; every field assertion now gets the
standard `DEFAULT_TIMEOUT * 3`.
- `transaction.spec.ts:80` (input data tab) — the "Input Data" tab
lives inside `TxAnalyser`, which only mounts once `hasInputData`
is true — derived from the receipt, which arrives after
`waitForTxContent`. Explicit timeout on the tab assertion.
Re-run result on my local machine (public RPC, parallel workers):
before — 5 failed; after — 2 failed + 2 flaky (same tests), 51 passed.
The remaining 2 (USDC 2022 approval tx, Arbitrum V3 swap) appear to
hit an app-side stale-data bug when the public RPC returns a null /
partial tx — out of scope for e2e stability tuning.
…Price locator
Deep-dive on the last 2 "pre-existing" failures: the app is behaving
correctly in both cases; the tests had bugs.
1) `transaction.spec.ts` / `mainnet.ts` — the `USDC_APPROVAL` constant
pointed to `0xc55e2b90168af69721…`. The fixture entry for that hash
in `mainnet.ts` described it as a Type-2 USDC approval at block
15,537,394 with `hasInputData: true`. On-chain reality (verified
directly against a public RPC): that hash resolves to a **2016
Binance transfer at block 2,000,000** with `input: "0x"` (no
calldata). USDC did not deploy until 2018, so the fixture metadata
was fabricated.
The "displays transaction with input data" test looks for the
"Input Data" tab inside `TxAnalyser`, which only mounts when
`hasInputData` is true — derived from the actual tx.input byte
length. Against real RPCs it therefore never rendered and the test
timed out. Replace `USDC_APPROVAL` with `TX_WITH_INPUT_DATA`
pointing to `0xbb4b3fc2…` (the EIP-1559 tx at block 20M already
pinned in the fixture and verified to have 242 bytes of input
data). Remove the stale USDC entry from `mainnet.ts` with a
comment explaining what was wrong, so nobody reads the old
metadata and re-imports it.
2) `arbitrum.spec.ts:250` — the locator
`locator(".tx-label", { hasText: "Gas Price:" })` matches two
spans on Arbitrum post-Nitro pages: `Gas Price:` AND
`Effective Gas Price:` (receipt vs. tx). Playwright's
`toBeVisible` in strict mode fails when the locator resolves to
multiple elements. My first fix attempt (`/^Gas Price:$/`) also
failed because the span's textContent is `"Gas Price:" +` the
HelperTooltip's text — the span is not a pure text node. Use a
start-anchored regex `/^Gas Price:/` (no `$`) so the match
allows the tooltip suffix but still excludes the "Effective"-
prefixed sibling.
Re-ran both specs in isolation: 8/8 passed in 1.3m. The refactor-
scoped suite also still passes unchanged. Zero changes to the app.
feat(tokenDetails): ERC721 token navigation and recent tokens list
fix(worker): anchor CORS origin allowlist to prevent Netlify-tenant abuse
refactor(e2e): cross-network test coverage + scaffolding
MatiasOS
approved these changes
Apr 28, 2026
fix(security): address H-1, H-2, M-3, M-4 from security review
11 tasks
Storacha's add-to-web3 action uses different UnixFS encoding parameters (1 MiB raw-leaf chunks) than our local Kubo setup (256 KiB UnixFS-wrapped chunks), producing mismatched CIDs between local and CI builds. Replace Storacha with Kubo in the CI workflow to ensure identical IPFS hashes in both environments. Also guard the local build script's IPFS commands behind a Kubo availability check.
chore: cherry-pick main commits to resolve dev conflicts (unblocks #360)
Audit (`scripts/audit.sh` → `npm audit --audit-level=moderate`) was failing with 16 vulnerabilities (5 moderate, 11 high), all from transitive deps. The audit has been red since before this release cycle started — this commit clears it. Direct devDeps bumped: - `vite`: `^7.3.1` → `^7.3.2` (3 CVEs: fs.deny bypass, path traversal in optimized-deps `.map`, ws arbitrary file read) - `happy-dom`: `^20.1.0` → `^20.8.9` (export-name code injection, fetch credentials origin bug) Existing override updated: - `axios`: `^1.15.0` → `^1.15.2` (13 CVEs in 1.15.0–1.15.1, mostly prototype-pollution gadgets and SSRF) New transitive overrides (parents haven't bumped upstream yet): - `bn.js >=5.2.3` (infinite loop) - `brace-expansion >=1.1.13` (zero-step sequence DoS) - `defu ^6.1.5` (proto-pollution via __proto__) - `follow-redirects ^1.15.12` (cross-domain auth header leak) - `h3 ^1.15.9` (path traversal, SSE injection variants) - `hono ^4.12.16` (XSS, cookie injection, IP-restriction bypass, etc.) - `lodash ^4.17.24` (proto-pollution, code-injection via _.template) - `minimatch >=3.1.4` (ReDoS via repeated wildcards) - `picomatch >=2.3.2` (method injection in POSIX char classes) - `postcss ^8.5.10` (XSS via unescaped </style>) - `rollup ^4.59.0` (path traversal arbitrary file write) - `socket.io-parser ^4.2.6` (unbounded binary attachments) - `yaml ^2.8.3` (stack overflow via deeply nested collections) Nested override: - `vitest > vite ^7.3.2` — vitest 4.0.14 pinned its inner vite to 7.3.1 specifically, separate from the project's direct vite. A top-level override conflicts with the direct dep, so use the per-parent `overrides.vitest.vite` form to force vitest's nested copy onto 7.3.2. Verified locally: - `npm run audit` → 0 vulnerabilities. - `npm run typecheck` → clean. - `npm run test:run` → 100/100 unit tests pass.
chore(deps): clear npm audit failures via direct bumps + transitive overrides
11 tasks
chore: bump version to 1.2.6-alpha
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Release v1.2.6-alpha — merges all changes from dev into main for the next production deployment.
Type of Change
Changes Made
New Features
SolanaClientfrom@openscan/network-connectors1.7 with multiple public RPC fallbacks (feat(solana): add Solana network support (Mainnet, Devnet, Testnet) #358)@openscan/metadatav1.2.1-alpha.0 and routed to their L1-family adapters inAdapterFactory(feat(networks): add 5 EVM testnets from metadata v1.2.1-alpha.0 #361)Bug Fixes
link-accentclass for in-app links, three-stat dashboard (price / slot / epoch), shared tx-list pattern for block transactions, restyled program logs sectionUSDC_APPROVALconstant pointed to a hash that on-chain is a 2016 Binance transfer with no input data (USDC didn't deploy until 2018), and the Arbitrum "Gas Price" locator matched bothGas Price:andEffective Gas Price:triggering Playwright strict-modeSecurity
pull_request_targetPR-preview workflow (which checked out and built untrusted PR code withNETLIFY_AUTH_TOKENin scope) with a splitpull_requestbuild +workflow_rundeploy pair. The deploy job never executes PR code, validates PR number / SHA before use, and passes values into shell andgithub-scriptviaenv:/process.envto avoid context-expression injection (fix(security): address H-1, H-2, M-3, M-4 from security review #365 H-1)toSafeExternalHrefhelper that rejectsjavascript:,data:,vbscript:,file:, and non-http(s) schemes and rewritesipfs://to the HTTPS gateway. Gateexternal_url,animation_url, andtokenUrihrefs on the ERC-721 and ERC-1155 detail pages (fix(security): address H-1, H-2, M-3, M-4 from security review #365 H-2)nwtgck/actions-netlify,JS-DevTools/npm-publish,oven-sh/setup-bun,biomejs/setup-biomeall pinned to 40-char commit SHAs with trailing# vNcomments. Add.github/dependabot.ymlforgithub-actionsso SHA bumps land as reviewable PRs (fix(security): address H-1, H-2, M-3, M-4 from security review #365 M-3). Note:storacha/add-to-web3was originally pinned in fix(security): address H-1, H-2, M-3, M-4 from security review #365 but is dropped from the workflow by the Kubo migration sync below.console.*: strings run throughredactSensitiveUrlsInText,Errorinstances rebuilt with scrubbed.message/.stack. PromotesredactSensitiveUrlout ofRpcTestRow.tsxinto a shared utility insrc/utils/urlUtils.ts(fix(security): address H-1, H-2, M-3, M-4 from security review #365 M-4)Refactoring
e2e/fixtures/networks.ts,localStorage.ts,rpcMock.ts,assertions.ts,assertionsL2.ts), cross-network shared specs (search, errors, settings, NFT safety, contract interaction, AI panel, event logs), L2 adapter-field assertions (Arbitruml1BlockNumber/sendCount/sendRoot, OP-stackl1Fee/l1GasPrice/l1GasUsed), and smoke coverage for previously orphaned production networks (Avalanche, Solana) and all 6 EVM testnets. Also fixes 5 pre-existing flaky mainnet specs (refactor(e2e): cross-network test coverage + scaffolding #366)EVM_TESTNET_CLIENTSto return the client union instead ofunknownsoAdapterFactory.createAdapterkeeps its strict client union, and narrowPolygonAdapter's constructor fromSupportedChainIdto137 | 80002to match sibling L2 adaptersREACT_APP_*environment variables withOPENSCAN_*and switch toimport.meta.envinstead ofprocess.envfor runtime access. AddenvPrefix: "OPENSCAN_"to Vite config soOPENSCAN_*vars are auto-exposed without manualdefineentries (refactor: migrate REACT_APP_ env vars to VITE_ prefix #347, refactor: migrate REACT_APP_ env vars to OPENSCAN_ prefix #353)CI/CD
e2e-shared.yml(6-shard matrix for cross-network specs),e2e-solana.yml,e2e-testnets.yml, pluse2e-nightly.yml(06:00 UTC cron callinge2e-all.yml, explicitly non-blocking)avalancheandl2-fieldsshards added so adapter-specific assertions and the previously-orphaned Avalanche network are gated on every PRdependencies+github-actionslabelsfix(ci): replace Storacha with Kubo for consistent IPFS hash generation— Storacha'sadd-to-web3action used different UnixFS encoding parameters than local Kubo, producing mismatched CIDs between local and CI builds (fix(ci): replace Storacha with Kubo for IPFS hash generation #321 on main)CI: Update actions/checkout and actions/setup-node to @v5(Fix npm publish github action #349 on main)Checklist
Additional Notes
workerConfig.tslists both and falls through on 429 / 502 / 503 / network errors.EVMAdapterdirectly except where adapter-specific behavior applies (Arbitrum Sepolia →ArbitrumAdapter, OP / Base Sepolia → their respective L2 adapters, Polygon Amoy →PolygonAdapter).package.jsonversion bump to1.2.6-alphashould land as part of this merge.STORACHA_PRINCIPAL,STORACHA_PROOF) are no longer referenced by any workflow ondevand can be removed from repo secrets after merge.