Skip to content

Fix/ci pipeline green - #88

Merged
tech-adrian merged 30 commits into
mainfrom
fix/ci-pipeline-green
Jul 26, 2026
Merged

Fix/ci pipeline green#88
tech-adrian merged 30 commits into
mainfrom
fix/ci-pipeline-green

Conversation

@tech-adrian

Copy link
Copy Markdown
Contributor

fix: get the CI pipeline green

Fixes every failing job in .github/workflows/ci.yml. Three of the six jobs
were failing; two were failing before they ran a single check.

Branch: fix/ci-pipeline-greendev

Why CI was red

1. Circuit fixtures were stale after domain separation (circuits, e2e)

PR #82 introduced Poseidon2 domain separation — LEAF_DOMAIN,
NULLIFIER_DOMAIN, KYC_DOMAIN — and moved the leaf, nullifier and KYC
hashes to 3-input hash3. The Prover.toml fixtures were never regenerated,
so all three circuits failed to solve:

Circuit Failing constraint
shielded_pool assert(nf == nullifier_hash)
compliance assert(computed_kyc == kyc_hash)
disclosure assert(computed_kyc == kyc_hash)

root, nullifier_hash and kyc_hash were recomputed using the circuits'
own hash functions against poseidon v0.2.0, rather than hand-written. The
same stale values were hardcoded a second time in tests/e2e.sh.

A false-pass bug hid this. tests/e2e.sh ran bb prove and bb verify
unconditionally after nargo execute, so when execute failed they succeeded
against the previous run's leftover witness and reported
PASS Proof verified locally. A broken circuit fixture could report a
verified proof. The script now clears the stale witness first, so a witness
failure can't be laundered into a passing proof.

2. Broken lockfile (lint, frontend)

frontend/pnpm-lock.yaml had an importer entry for
@next/bundle-analyzer@16.2.12 with no matching packages:/snapshots:
record — a badly resolved merge conflict from #86. --frozen-lockfile, which
CI uses, failed outright:

ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY: Broken lockfile: no entry for
'@next/bundle-analyzer@16.2.12(bufferutil@4.1.0)(utf-8-validate@6.0.6)'

This blocked both jobs at install, before lint or build ran.

3. Type and lint errors (lint, frontend)

  • ThresholdDisclosure.tsx imported generateThresholdProof, removed in perf: move client-side proof generation off the main thread #71.
  • (totalNotes * selectedTier?.amount ?? 0) parses as (a * b) ?? 0, so the
    fallback never applied and undefined could reach the multiply. This only
    surfaced once the import error stopped masking it.
  • Three (window as any).__pendingNotes casts failed no-explicit-any.

Deposits could never be signed

Rendering-related, and the most user-visible fix here. ConfirmDeposit was
defined but never rendered, so signAndSubmit was unreachable —
handleDeposit built and staged a transaction that had no path to the
wallet. The deposit flow silently did nothing.

Rendering it surfaced three further defects:

  • Unstable component identity. ConfirmDeposit was created during render,
    so React remounted it on every parent update
    (react-hooks/static-components). Hoisted to module scope as a
    props-driven component. Harmless only while it was dead code.
  • Wrong total displayed. The modal read totalNotes, derived from
    customAmount, which handleDeposit clears in its finally before the
    user confirms — a 5-note deposit showed the 1-note total. The count is now
    captured at build time in confirmNoteCount.
  • Cancel left state staged. Cancel only did setShowConfirm(false),
    leaving pendingTx and the pending notes live, so a cancelled deposit's
    transaction could be submitted by a later confirmation. Cancel now clears
    both, matching the post-submit cleanup.

Also

Adds **/test_snapshots/ to .gitignore and untracks the generated Soroban
snapshot files.

Worth a reviewer's opinion: these are conventionally committed — they're how
unintended changes in contract resource usage get caught across builds.
Untracking them means CI regenerates them each run and that diff signal goes
away. Happy to drop this from the PR if you'd rather keep them tracked.

Deliberately not fixed

ThresholdDisclosure is left as an explicit throw, not a rename to
proveDisclosure. The replacement needs the auditor key, KYC
preimage/hash, merkle root and merkle path — none derivable from a
ShieldedNote. Wiring it up means writing the disclosure input-assembly
logic, not a mechanical rename, and inventing ZK inputs to satisfy the
compiler would be worse than the build error. The component is currently
rendered nowhere and proveDisclosure has no callers. A comment in the file
records what's needed.

Verification

Every CI job was run locally end to end:

Job Result
Security Audit cargo audit — 0 vulnerabilities
Circuit Tests 3/3 compile, execute, prove, verify
Contract Tests 125 passed; stellar contract build OK
Lint 0 errors
Frontend pnpm audit OK, 113 tests passed, build OK
E2E Tests 26/26 passed

Remaining lint output is 2 pre-existing warnings (KYC_DOMAIN in
poseidon2.ts; setProof in the stubbed disclosure component). pnpm audit
reports 1 low-severity advisory — the documented elliptic issue with no
upstream fix, below the --audit-level=moderate gate.

Not covered: there's no test for the confirm modal, and the wallet-signing
path wasn't driven in a browser. The state transitions are traced and correct
and the build/lint/test suite passes, but the real signing flow deserves a
manual pass against the dev server (port 3001) before merge.

Commits

  • 6633f4c fix(circuits): regenerate Prover.toml fixtures for domain-separated Poseidon2
  • f2c204c fix(frontend): repair broken pnpm-lock.yaml entry for @next/bundle-analyzer
  • 0409cda fix(deposit): render the confirmation modal so deposits can be signed

tech-adrian and others added 30 commits July 21, 2026 21:30
All PRs are now required to target dev instead of main, but the
workflow only ran on push/pull_request to main. As a result every
open PR against dev has "no checks reported" and nothing gates
merges into dev.
…findings (#53)

* fix(frontend): pin axios and bump protobufjs override to close audit findings

pnpm audit --prod --audit-level=moderate has been failing CI's Frontend
job (once CI actually ran against dev, see #52) with 12 findings:
- axios <1.18.0 resolved at three different versions transitively via
  @creit.tech/stellar-wallets-kit's wallet-connector chain (cdp-sdk,
  stellar-sdk). Pinned to ^1.18.1, which was already resolving
  elsewhere in the tree via @stellar/stellar-sdk, so no new major
  version is introduced.
- protobufjs's existing override (^7.6.3) predates GHSA-j3f2-48v5-ccww
  (fixed in 7.6.5); bumped the pin to ^7.6.5, same patch-only policy
  already used for this override.

Verified: pnpm audit --prod --audit-level=moderate now exits 0 (only
the pre-existing, already-documented unpatched elliptic advisory
remains), and pnpm test / pnpm lint / pnpm build all still pass.

* fix(e2e): strip JSON string quoting from i128 CLI output before comparing

get_deposit_amount returns i128 (contracts/pool/src/lib.rs:550). The
Stellar CLI JSON-encodes 64+ bit integers as quoted strings to avoid
JS precision loss, unlike get_next_index's plain u32 output. The
comparison was failing every run with expected 10000000, got
"10000000" (quotes included) since this test never actually executed
in CI before dev branch runs were enabled (#52).
- Add husky ^9.1.7 and lint-staged ^15.5.2 to frontend/package.json devDependencies
- Add prepare script so pnpm install auto-installs the git hook
- Configure lint-staged to run eslint --fix on staged src/**/*.{ts,tsx} files
- Add frontend/.husky/pre-commit hook that runs pnpm lint-staged
- Add CONTRIBUTING.md (absent from dev branch) with husky setup documented:
  one-time setup note after pnpm install step, updated step 5 to mention
  the hook runs automatically on commit

Closes #25
- Add 'Deployment Limitations' section to SECURITY.md with a dedicated
  'Rate Limiter — Single-Instance Only' subsection that explains:
  - The in-memory, per-process nature of checkRateLimit
  - Why multi-instance deployments (load balancer, HPA) get no real protection
  - Upgrade path: Upstash Redis, self-hosted Redis, or Vercel KV
- Add a ⚠️ callout to the README.md Security Model section linking to
  the new SECURITY.md anchor for the full upgrade path

Closes #16
…diagram #51 (#47)

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
…ons (#50)

* Add community templates and documentation

- Add GitHub issue templates (bug report, feature request, config)
- Add pull request template
- Add CODE_OF_CONDUCT.md for community standards
- Add CONTRIBUTING.md with contribution guidelines
- Add SECURITY.md for security policy
- Update README.md
- Remove outdated PR.md

* chore: reports md

* docs: require PRs target dev branch, not main

Issue templates, PR template, and CONTRIBUTING.md now consistently
point contributors at `dev` as the base/target branch.

* docs: add GLOSSARY.md with plain-English ZK and Soroban term definitions

Covers: nullifier, commitment, Merkle root/tree, Merkle inclusion proof,
ZKP, zkSNARK, UltraHonk, Noir, Barretenberg, verification key, Poseidon2,
keccak transform, BN254, selective disclosure, recipient binding, note,
client-side prover, Stellar, Soroban, relayer, shielded pool, SAC, Freighter.

Linked from README.md (new 'New to ZK or Stellar?' section near top +
glossary link in Contributing paragraph) and CONTRIBUTING.md (callout
block after intro + entry in 'Where things live' list).

All 204 tests pass (107 Rust/Soroban + 97 frontend Vitest).

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
Co-authored-by: ShantelPeters <shantelpeters@example.com>
…ips CVE (#54)

pnpm audit --prod --audit-level=moderate started failing again with a
fresh advisory (GHSA-f88m-g3jw-g9cj, libvips CVEs in sharp <0.35.0).
next@16.2.9 declares sharp as ^0.34.5, which under semver caret rules
for 0.x versions excludes the patched 0.35.x line entirely, so pnpm
was resolving the vulnerable version by default.

Overrode to ^0.35.3. Verified: pnpm audit exits 0 (only the
pre-documented elliptic advisory remains), pnpm build succeeds
(exercises sharp via /icon.png generation), pnpm test (97/97) and
pnpm lint pass.
* Add community templates and documentation

- Add GitHub issue templates (bug report, feature request, config)
- Add pull request template
- Add CODE_OF_CONDUCT.md for community standards
- Add CONTRIBUTING.md with contribution guidelines
- Add SECURITY.md for security policy
- Update README.md
- Remove outdated PR.md

* chore: reports md

* docs: require PRs target dev branch, not main

Issue templates, PR template, and CONTRIBUTING.md now consistently
point contributors at `dev` as the base/target branch.

* docs: add pull request template with required sections

- Added Why section (CONTRIBUTING.md requirement: describe why, not just what)
- Renamed Testing to Testing done for clarity
- Added Screenshot / recording (required) section
- Added Related issue section with Closes # placeholder
- Replaced Area section with Why to match issue #41 acceptance criteria
- Replaced Breaking changes section with Screenshot/recording requirement

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
… guides (#48)

* Add community templates and documentation

- Add GitHub issue templates (bug report, feature request, config)
- Add pull request template
- Add CODE_OF_CONDUCT.md for community standards
- Add CONTRIBUTING.md with contribution guidelines
- Add SECURITY.md for security policy
- Update README.md
- Remove outdated PR.md

* chore: reports md

* docs: require PRs target dev branch, not main

Issue templates, PR template, and CONTRIBUTING.md now consistently
point contributors at `dev` as the base/target branch.

* chore: add documented frontend/.env.local.example template and update guides

* docs: add CHANGELOG.md and update contributor guidelines #6

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
* wip: add axe-core a11y regression tests (pnpm-lock.yaml pending install)

* fix: correct file input label and fix broken tag-input in NoteImport

* ci: retrigger checks

---------

Co-authored-by: YerimahOfTimes <yerimahjr@gmail.com>
Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
* Add community templates and documentation

- Add GitHub issue templates (bug report, feature request, config)
- Add pull request template
- Add CODE_OF_CONDUCT.md for community standards
- Add CONTRIBUTING.md with contribution guidelines
- Add SECURITY.md for security policy
- Update README.md
- Remove outdated PR.md

* chore: reports md

* docs: require PRs target dev branch, not main

Issue templates, PR template, and CONTRIBUTING.md now consistently
point contributors at `dev` as the base/target branch.

* feat: enhanced mobile responsiveness

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
* contracts: add paginated get_commitments_page view

get_commitments() reads every leaf in one invocation and has no bound
other than MAX_LEAVES (2^20), so it will exceed Soroban's per-transaction
CPU/footprint limits once a pool grows enough, making client-side tree
reconstruction unbuildable. get_commitments_page(start, limit) returns a
bounded, on-chain-capped (MAX_PAGE_SIZE = 100) range instead.

Covers: a page landing exactly on next_index, an out-of-range start, and
a limit above the enforced max.

Refs #57

* frontend: page through get_commitments_page for tree reconstruction

fetchCommitmentsFromChain (used by both the withdraw flow and the
compliance report) now pages through the pool contract's new
get_commitments_page view instead of calling the unbounded
get_commitments(), so client-side Merkle tree reconstruction keeps
working as a pool grows past what a single get_commitments() call can
return.

Any page-call failure returns null rather than a partial list, since a
truncated commitment set would silently reconstruct the wrong root.

Refs #57

* docs: describe paginated get_commitments_page in Security Model

Adds a fourth Security Model property documenting trustless tree
reconstruction via get_commitments_page and its on-chain MAX_PAGE_SIZE
ceiling, plus a CHANGELOG entry.

Refs #57
* Add community templates and documentation

- Add GitHub issue templates (bug report, feature request, config)
- Add pull request template
- Add CODE_OF_CONDUCT.md for community standards
- Add CONTRIBUTING.md with contribution guidelines
- Add SECURITY.md for security policy
- Update README.md
- Remove outdated PR.md

* chore: reports md

* docs: require PRs target dev branch, not main

Issue templates, PR template, and CONTRIBUTING.md now consistently
point contributors at `dev` as the base/target branch.

* perf: extract proof generation into a worker-ready core module

Split prover.ts's Noir.execute/UltraHonkBackend.generateProof logic into
prover-core.ts (a pure async function with progress hooks) plus a new
prover.worker.ts Web Worker entry point that runs it off the main thread.
Neither is wired up to the public API yet — that's the next commit.

* perf: dispatch proof generation to a Web Worker

prover.ts now posts circuit + inputs to prover.worker.ts and resolves once
the worker replies, forwarding progress updates ("executing" / "proving")
via an optional onProgress callback. Falls back to the inline core
function when Worker isn't available (SSR, unit tests), so behavior is
unchanged outside the browser.

Fixes #26: proof generation (Noir witness execution + UltraHonk proving)
no longer runs on the main thread, so the UI stays responsive — scrollable,
spinner animating — for the ~1 minute a deposit/withdraw/compliance proof
can take.

* test: cover prover.ts input mapping and progress reporting

Exercises the inline fallback path (no Worker global in the test
environment) with mocked Noir/UltraHonkBackend: verifies hex-prefixing of
note fields, executing/proving progress order, and that the backend is
destroyed even when proving throws.

* feat(withdraw): show which proving stage is running

Surfaces the worker's executing/proving progress as a finer-grained label
under the existing spinner during the "generating_proof" step, so users
get feedback for the full duration of proof generation rather than a
single static message.

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
…ructor (#76)

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
* feat(frontend): add CSV/JSON formatters for activity history

Adds formatActivityCsv/formatActivityJson to lib/report.ts, alongside a
shared ActivityItem type, so the history page's activity feed can be
exported as a portable file for auditors/regulators. Column/field list
is documented inline above the formatters.

* test(frontend): cover CSV/JSON activity export formatting

Checks header/row shape, blank amount/pool fields on compliance rows,
CSV comma-escaping, and JSON round-tripping.

* feat(frontend): add Export CSV/JSON action to History page

Wires the new formatters into the history page: an Export row (styled
like the compliance page's download link) sits above the activity
list and downloads whatever the active filter shows. Export always
covers the full filtered set, not just the rows the infinite-scroll
pager has revealed so far — pagination is a rendering optimization,
not a data window.

Closes #13

* docs: log CSV/JSON history export in CHANGELOG

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
* a11y: add aria labels and semantic HTML to Input component

* a11y: enhance ProgressSteps with semantic markup and aria attributes

* a11y: improve StatusMessage component with roles and live region support

* a11y: add role and aria attributes to Toast notifications

* a11y: refactor deposit page with semantic HTML and improved accessibility labels

* a11y: enhance compliance page with fieldsets, legends, and improved accessibility
* test(pool): add named recipient-mismatch rejection test

test_withdraw_to_different_recipient_than_proof_rejected builds public
inputs carrying the genuine recipient hash of account A, then submits
the withdrawal with account B as the payout address, asserting
RecipientMismatch. This is the front-running redirect case: unlike the
existing test_withdraw_recipient_mismatch_rejected, which uses a filler
hash, the proof here is bound to a real, different account.

* test(pool): add named double-spend replay rejection test

test_replaying_consumed_nullifier_returns_nullifier_used replays a
withdrawal proof whose nullifier has already been consumed and asserts
NullifierUsed. It first confirms the same proof is not rejected on the
nullifier before the spend, so the rejection is attributable to the
replay rather than an unrelated check.

* docs(readme): cite double-spend and recipient-binding tests by name

The Security Model section named the tests locking hash consistency but
not the ones covering nullifier consumption or recipient binding, both
of which it claimed were covered by tests. Cite them by name so the
claim is traceable to the tests that enforce it.
* Add community templates and documentation

- Add GitHub issue templates (bug report, feature request, config)
- Add pull request template
- Add CODE_OF_CONDUCT.md for community standards
- Add CONTRIBUTING.md with contribution guidelines
- Add SECURITY.md for security policy
- Update README.md
- Remove outdated PR.md

* chore: reports md

* docs: require PRs target dev branch, not main

Issue templates, PR template, and CONTRIBUTING.md now consistently
point contributors at `dev` as the base/target branch.

* sec remove o the public X share option for note-bearing withdrawal links (#74)

* fix: await clipboard write and surface error instead of false Copied! (closes #68) (#70)

* Feature: deposit confirmation (#56)

* feat: add threshold disclosure UI and integration

* Add explicit amount and fee confirmation before deposit signing

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>

* Chore/add env example 28 (#51)

* chore: add documented frontend/.env.local.example template and update guides

* docs: add CHANGELOG.md and update contributor guidelines #6

* fix(ci): trigger CI on dev branch, not just main (#52)

All PRs are now required to target dev instead of main, but the
workflow only ran on push/pull_request to main. As a result every
open PR against dev has "no checks reported" and nothing gates
merges into dev.

* fix(frontend): pin axios and bump protobufjs override to close audit findings (#53)

* fix(frontend): pin axios and bump protobufjs override to close audit findings

pnpm audit --prod --audit-level=moderate has been failing CI's Frontend
job (once CI actually ran against dev, see #52) with 12 findings:
- axios <1.18.0 resolved at three different versions transitively via
  @creit.tech/stellar-wallets-kit's wallet-connector chain (cdp-sdk,
  stellar-sdk). Pinned to ^1.18.1, which was already resolving
  elsewhere in the tree via @stellar/stellar-sdk, so no new major
  version is introduced.
- protobufjs's existing override (^7.6.3) predates GHSA-j3f2-48v5-ccww
  (fixed in 7.6.5); bumped the pin to ^7.6.5, same patch-only policy
  already used for this override.

Verified: pnpm audit --prod --audit-level=moderate now exits 0 (only
the pre-existing, already-documented unpatched elliptic advisory
remains), and pnpm test / pnpm lint / pnpm build all still pass.

* fix(e2e): strip JSON string quoting from i128 CLI output before comparing

get_deposit_amount returns i128 (contracts/pool/src/lib.rs:550). The
Stellar CLI JSON-encodes 64+ bit integers as quoted strings to avoid
JS precision loss, unlike get_next_index's plain u32 output. The
comparison was failing every run with expected 10000000, got
"10000000" (quotes included) since this test never actually executed
in CI before dev branch runs were enabled (#52).

* docs: add api route request/response contracts (#39)

* chore: add husky + lint-staged pre-commit hook for frontend (#40)

- Add husky ^9.1.7 and lint-staged ^15.5.2 to frontend/package.json devDependencies
- Add prepare script so pnpm install auto-installs the git hook
- Configure lint-staged to run eslint --fix on staged src/**/*.{ts,tsx} files
- Add frontend/.husky/pre-commit hook that runs pnpm lint-staged
- Add CONTRIBUTING.md (absent from dev branch) with husky setup documented:
  one-time setup note after pnpm install step, updated step 5 to mention
  the hook runs automatically on commit

Closes #25

* docs: add CODEOWNERS file (#41)

* docs(security): document rate limiter single-instance limitation (#42)

- Add 'Deployment Limitations' section to SECURITY.md with a dedicated
  'Rate Limiter — Single-Instance Only' subsection that explains:
  - The in-memory, per-process nature of checkRateLimit
  - Why multi-instance deployments (load balancer, HPA) get no real protection
  - Upgrade path: Upstash Redis, self-hosted Redis, or Vercel KV
- Add a ⚠️ callout to the README.md Security Model section linking to
  the new SECURITY.md anchor for the full upgrade path

Closes #16

* docs: replace the ASCII architecture diagram with a rendered Mermaid diagram #51 (#47)

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>

* docs: add GLOSSARY.md with plain-English ZK and Soroban term definitions (#50)

* Add community templates and documentation

- Add GitHub issue templates (bug report, feature request, config)
- Add pull request template
- Add CODE_OF_CONDUCT.md for community standards
- Add CONTRIBUTING.md with contribution guidelines
- Add SECURITY.md for security policy
- Update README.md
- Remove outdated PR.md

* chore: reports md

* docs: require PRs target dev branch, not main

Issue templates, PR template, and CONTRIBUTING.md now consistently
point contributors at `dev` as the base/target branch.

* docs: add GLOSSARY.md with plain-English ZK and Soroban term definitions

Covers: nullifier, commitment, Merkle root/tree, Merkle inclusion proof,
ZKP, zkSNARK, UltraHonk, Noir, Barretenberg, verification key, Poseidon2,
keccak transform, BN254, selective disclosure, recipient binding, note,
client-side prover, Stellar, Soroban, relayer, shielded pool, SAC, Freighter.

Linked from README.md (new 'New to ZK or Stellar?' section near top +
glossary link in Contributing paragraph) and CONTRIBUTING.md (callout
block after intro + entry in 'Where things live' list).

All 204 tests pass (107 Rust/Soroban + 97 frontend Vitest).

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
Co-authored-by: ShantelPeters <shantelpeters@example.com>

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
Co-authored-by: Emelie-Dev <120989028+Emelie-Dev@users.noreply.github.com>
Co-authored-by: benzy018 <akobezjr@gmail.com>
Co-authored-by: Fadila Bala Usman <fadilausman705@gmail.com>
Co-authored-by: Joyful Analyst <joyonyegbuna2020@gmail.com>
Co-authored-by: Joey <62303285+Mona-i@users.noreply.github.com>
Co-authored-by: Shantel peters. <Elizabethogunrinde2015@gmail.com>
Co-authored-by: ShantelPeters <shantelpeters@example.com>

* feat: add threshold disclosure UI and integration (#55)

* feat(circuits): add domain separation to Poseidon2 leaf/node/KYC/nullifier hashing

- Add domain-separated hash functions using distinct tags:
  - LEAF_DOMAIN (0x4c454146) for leaf hashes
  - KYC_DOMAIN (0x4b5943) for KYC preimage hashes
  - NULLIFIER_DOMAIN (0x4e554c4c) for nullifier hashes
- Update hash_leaf() to use hash3(LEAF_DOMAIN, nullifier, secret)
- Update hash_kyc() to use hash3(KYC_DOMAIN, kyc_preimage, 0)
- Update hash_nullifier() in shielded_pool to use hash3(NULLIFIER_DOMAIN, nullifier, 0)
- Internal nodes continue to use undifferentiated hash2(left, right)

This prevents the classic Merkle tree collision anti-pattern where commitments
stored on-chain via get_commitments() could be confused with internal nodes.
Each domain tag ensures cryptographic separation between different hash contexts.

* feat(frontend): update Poseidon2 hashing for domain separation

- Add domain separation constants matching circuit definitions:
  - LEAF_DOMAIN, KYC_DOMAIN, NULLIFIER_DOMAIN
- Update computeCommitment() to compute domain-separated leaf hashes
- Update computeNullifierHash() to compute domain-separated nullifier hashes
- Update test expected values for new domain-separated hash outputs

Note: Frontend approximates hash3 via sequential hash2 calls to work with
existing hasher circuit. A future optimization could use a native Poseidon2
library for true hash3 computation, but current approach maintains consistency
with circuit behavior.

* Fix syntax error in deposit page after merge

Remove extra closing brace that broke copyText function structure.

---------

Co-authored-by: tech-adrian <a.emmanuelcaxton@gmail.com>
Co-authored-by: Darey Olowo <132012676+Olowodarey@users.noreply.github.com>
Co-authored-by: SpiliosDmk <150211937+SpiliosDimakopoulos@users.noreply.github.com>
Co-authored-by: Ugooweb <ugooweb@gmail.com>
Co-authored-by: Sanusi Shafii <sanusishafii989@gmail.com>
Co-authored-by: Emelie-Dev <120989028+Emelie-Dev@users.noreply.github.com>
Co-authored-by: benzy018 <akobezjr@gmail.com>
Co-authored-by: Fadila Bala Usman <fadilausman705@gmail.com>
Co-authored-by: Joyful Analyst <joyonyegbuna2020@gmail.com>
Co-authored-by: Joey <62303285+Mona-i@users.noreply.github.com>
Co-authored-by: Shantel peters. <Elizabethogunrinde2015@gmail.com>
Co-authored-by: ShantelPeters <shantelpeters@example.com>
- Convert static top-level circuit JSON imports in prover.ts to
  dynamic import() calls so each artifact is only fetched when the
  matching prove* function is first called (not on initial page load).
  Named webpack chunk hints (circuit-shielded-pool, circuit-compliance,
  circuit-disclosure) are added to preserve readable chunk names.

- Move @noir-lang/noir_js and @aztec/bb.js imports inside generateProof()
  so the heavy barretenberg WASM is also deferred until proof generation.

- Add @next/bundle-analyzer 16.2.12 to devDependencies; configure
  next.config.ts to enable it when ANALYZE=true.

- Add 'analyze' script to package.json (ANALYZE=true next build).

- Add frontend/BUNDLE_ANALYSIS.md documenting circuit artifact sizes
  (~9.7-10.8 KB each, 35.2 KB total), ZK runtime sizes, production
  build chunk sizes, per-page loading strategy, and instructions for
  re-running the analysis.

- Add frontend/src/lib/prover.test.ts with 34 unit tests covering the
  public API, ProofResult encoding, per-circuit bytecode routing,
  keccak: true flag, backend.destroy in finally, all input field
  mappings for all three circuits, and ensureHex behaviour.

All 131 frontend tests pass.

Closes #27
…oseidon2

PR #82 introduced domain separation (LEAF_DOMAIN, NULLIFIER_DOMAIN,
KYC_DOMAIN) and moved the leaf/nullifier/KYC hashes to 3-input Poseidon2,
but the Prover.toml fixtures kept their pre-domain-separation values. All
three circuits failed to solve:

  shielded_pool  assert(nf == nullifier_hash)
  compliance     assert(computed_kyc == kyc_hash)
  disclosure     assert(computed_kyc == kyc_hash)

Recomputed root, nullifier_hash and kyc_hash with the circuits' own hash
functions against poseidon v0.2.0, rather than hand-writing constants.
The same stale values were hardcoded a second time in tests/e2e.sh.

Also remove the stale witness/proof before `nargo execute` in e2e.sh. The
script ran `bb prove`/`bb verify` unconditionally after a failed execute,
so they succeeded against the *previous* run's artifacts and reported
"Proof verified locally" for inputs that never solved — which is how this
fixture breakage stayed green in CI.

All three circuits now compile, execute, prove and verify.
…alyzer

The importer referenced @next/bundle-analyzer@16.2.12 with no matching
packages:/snapshots: record — a badly resolved merge conflict from #86.
`pnpm install --frozen-lockfile`, which CI uses, failed outright:

  ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY: Broken lockfile: no entry for
  '@next/bundle-analyzer@16.2.12(bufferutil@4.1.0)(utf-8-validate@6.0.6)'

This blocked both the lint and frontend jobs before any check ran.
ConfirmDeposit was defined but never rendered, so signAndSubmit was
unreachable: handleDeposit built and staged a transaction that had no
path to the wallet. Deposits silently did nothing.

Rendering it surfaced three further defects:

- ConfirmDeposit was created during render, so React remounted it on
  every parent update (react-hooks/static-components). Hoisted to module
  scope as a props-driven component.
- The modal read `totalNotes`, derived from `customAmount`, which
  handleDeposit clears in its `finally` before the user confirms — a
  5-note deposit displayed the 1-note total. Capture the count at build
  time in `confirmNoteCount` instead.
- Cancel only did setShowConfirm(false), leaving pendingTx and the
  pending notes staged, so a cancelled deposit's transaction could be
  submitted by a later confirmation. Cancel now clears both.

Also fixes two type errors that blocked `next build`:

- `(totalNotes * selectedTier?.amount ?? 0)` parses as `(a * b) ?? 0`,
  so the fallback never applied and undefined could reach the multiply.
- ThresholdDisclosure imported generateThresholdProof, removed in #71.
  Its replacement, proveDisclosure, needs the auditor key, KYC
  preimage/hash, merkle root and path — none derivable from a
  ShieldedNote — so this is left as an explicit throw with a note on
  what wiring it up requires, rather than a rename over invented ZK
  inputs. The component is currently rendered nowhere.

Replaces three `(window as any).__pendingNotes` casts, which failed
no-explicit-any, with a typed useRef.

Adds **/test_snapshots/ to .gitignore and untracks the generated
Soroban snapshot files.
@tech-adrian
tech-adrian merged commit 1a7f25e into main Jul 26, 2026
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.