Skip to content

Audit fixes - #1

Open
radojevicMihailo wants to merge 144 commits into
mainfrom
develop
Open

Audit fixes#1
radojevicMihailo wants to merge 144 commits into
mainfrom
develop

Conversation

@radojevicMihailo

Copy link
Copy Markdown
Contributor

No description provided.

vanja-obradovic and others added 30 commits March 19, 2026 11:43
Implements complete Anchor program with deterministic PDAs, SECP256k1 recovery,
and atomic bridging via LiFi. Includes backend integration with SolanaPortalChainRepository
and SolanaPortalBroadcaster. Comprehensive tests and documentation included.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
vanja-obradovic and others added 28 commits June 24, 2026 15:57
…rce-only)

SEC-23: cap setProtocolFees at the intended max (lockstep with the circuit). DX-28: updateConfig reverts on a non-zero address lacking code + supports explicit unset. DX-30: remove the unused WithdrawalGasCostsUpdated event + dead mapping; correct NatSpec. OWNER FOLLOWUP: recompile + regenerate/publish ABIs + redeploy (UUPS); no key/verifier regen here.
…8, SEC-26)

Regenerated verifySingleAggregationNoHashing_2_3_30 (zkey/wasm/vkey) + CurvyAggregationVerifier.sol from the COR-8/SEC-26 circuit source (PTAU 15, 27412 constraints). Added a mainnet-scale (>999) fee fixture proving COR-8 is fixed — 700 SDK tests green. OWNER FOLLOWUP: this is a dev single-contribution key; production needs a proper trusted-setup ceremony, and the on-chain CurvyAggregationVerifier must be redeployed for the new vkey to take effect.
…r + key (COR-23, DX-31)

Regenerated verifyPendingNotesCommitment_5_30 (zkey/wasm/vkey, pot18) + CurvyPendingNotesCommitmentVerifier.sol from the COR-23 (leaf-indexing) + DX-31 (dead ComputeIndices removed) circuit source, so the deployed pending-notes verifier matches the committed circuit again. Also fixed build-pending-notes-commitment-5.sh: reorg'd verifier path (contracts/evm/src/v2/...), emit under the deployed CurvyPendingNotesCommitmentVerifier name, and PTAU 18 (226k constraints fit 2^18; pot20 was overkill). OWNER FOLLOWUP: dev single-contribution key — production needs a real ceremony; redeploy the on-chain verifier for the new vkey to take effect. Full proof validation is the devenv e2e suite.
…a; auto-resolve in aggregate

Aggregation with a non-zero protocol/gas fee needs a COLLECTABLE fee note (COR-12 made buildAggregationWitnessBundle throw on an uncollectable one), which requires the fee collector's full Curvy identity (S+V) — but the aggregator stores only the babyJubjub key on-chain. So:
- @0xcurvy/common: DEV_FEE_COLLECTOR (deterministic localnet identity, derived via Core.getCurvyKeys) + babyJubjubToXY.
- contracts deploy (devenv.ts): initFeeNotePublicKey sets the aggregator's feeNotePublicKey from the dev collector's babyJubjub at deploy:local (env FEE_COLLECTOR_BABYJUBJUB overrides for staging/prod).
- metadata: serves network.feeCollector {S,V,babyJubjub} on vault-enabled networks via /currency/latest (FEE_COLLECTOR_S/V/BABYJUBJUB config, defaults to the dev identity).
- SDK: Network.feeCollector type; buildAggregateRequest auto-resolves feeRecipient from the active network when the caller omits it, and asserts the resolved babyJubjub equals the on-chain feeNotePublicKey.
- devenv: the aggregate helper seals the fee note to DEV_FEE_COLLECTOR (+ setDevFeeNotePublicKey); all 6 v3 tests use the dev collector instead of a random per-test key.
Net: a fresh deploy:local configures the on-chain key, metadata serves the matching keys, and buildAggregateRequest with fees works with no feeRecipient at the call site.
…d (UnknownGasFeeRoot)

initPerTokenGasFees built the gas-fee tree from a dense [v1,v2] array (fromOrderedLeaves),
placing tokenId 1/2 at leaf 0/1 — but the SDK (fetchAggregatorFees) and the aggregation
circuit prove the input token's leaf at index = tokenId over the full 2^GAS_FEE_TREE_DEPTH
leaf set. So the deploy pushed a root the SDK's proof can never match → submitAggregation
reverts UnknownGasFeeRoot(). Build the root with leaf[tokenId] = pendingNoteCommitment
(zeros elsewhere), matching the vault's own documented reconstruction. The on-chain gasFees
array is unchanged (still one entry per registered token, so n <= _numberOfTokens holds);
only the locally-computed root changes. Verified on a live localnet: old root == on-chain
dense root; new root == the gas-fee root in the failing proof's public signals.
…degen + deploy_for_testing)

New ADDITIVE crate at packages/contracts/evm/bindings/curvy-bindings — a faithful
structural mirror of hoprnet's hopr-bindings 4.9.1, so blokli/hoprnet-side consumers
integrate Curvy through exactly the pattern they already use:

- src/codegen/**: committed `forge bind --alloy` output (forge 1.5.1 pinned), one
  snake_case module per contract: CurvyVaultV2, CurvyAggregatorAlphaV2, PortalFactory,
  Portal, the 3 Groth16 verifiers, PoseidonT4, ERC1967Proxy, ERC20Mock, Multicall3.
- src/config.rs: CurvyContractAddresses (named serde slots, DisplayFromStr) +
  CurvyContractInstances<P> with new(), get_contract_addresses() and
  deploy_for_testing(provider, deployer) doing the FULL validated pipeline (ported 1:1
  from rs-core sdk/curvy-deployer, not reinvented): CreateX bootstrap, PoseidonT4
  library link, UUPS impl+proxy pairs + initialize, verifier registration,
  PortalFactory via CreateX deployCreate2, wiring, dev funding, setPerTokenGasFees +
  setFeeNotePublicKey, read-back verification. to_ignition_json() keeps the exact
  downstream deployed_addresses.json key contract.
- src/constants.rs: CreateX signed deploy tx + canonical addresses, create2 salt,
  verifier dims, dev gas-fee table, PRECOMPUTED commitment-gas-fee root (arkworks
  stays out of this crate), DEV_FEE_COLLECTOR key, unlinked aggregator bytecode.
- bindings/generate.sh: deterministic regeneration (pinned forge, --check mode) with a
  hard bytecode PARITY GATE vs the Hardhat artifacts: all 11 contracts byte-identical
  modulo the solc CBOR metadata blobs (documented in the crate README; known
  consequence: the deterministic CREATE2 PortalFactory address moves, no consumer
  hardcodes it).
- foundry.toml + remappings.txt (package root): foundry profile mirroring
  hardhat.config.ts (solc 0.8.28/cancun/optimizer 200), node_modules remappings;
  forge output isolated under bindings/curvy-bindings/.forge so Hardhat dirs are
  untouched — the two toolchains coexist.

Version LOCKSTEP with this contracts package (1.0.0); policy in the crate README.
alloy pinned =2.1.0 like hopr-bindings (drops into blokli's alloy world).
cargo build + cargo test green (deploy_for_testing against a throwaway anvil,
read-back + ignition-key + determinism asserts).
# Conflicts:
#	.github/workflows/_deploy-backend.yaml
#	.github/workflows/_deploy-frontend.yaml
#	.github/workflows/deploy-backend-staging.yaml
#	.github/workflows/deploy-frontend-staging.yaml
#	frontend.Dockerfile
#	packages/@0xcurvy/sdk/src/actions/planner/estimateExternalTransfer.ts
#	packages/@0xcurvy/sdk/src/events.ts
#	packages/@0xcurvy/sdk/src/interfaces/events.ts
#	packages/@0xcurvy/sdk/src/types/events.ts
#	packages/backend/Dockerfile
#	packages/backend/package.json
#	packages/frontend/src/app/config/evm.ts
#	packages/frontend/src/app/context/CurvySdkContext.tsx
#	packages/frontend/src/app/hooks/AuthErrorBoundary.tsx
#	packages/frontend/src/app/hooks/extWallets/useSendFromWallet.ts
#	packages/frontend/src/app/store/portal-recovery.ts
#	packages/frontend/src/features/authentication/components/ProfileMenu.tsx
#	packages/frontend/src/features/portal-recovery/hooks/usePortalRecovery.ts
#	packages/frontend/src/features/publicPage/components/index.tsx
#	packages/frontend/src/features/receive/components/ReceiveTabs/StealthAddrTab.tsx
#	packages/frontend/src/features/receive/components/ReceiveTabs/index.tsx
#	packages/frontend/src/features/swap-public/components/DepositAwait.tsx
#	packages/frontend/src/features/swap-public/components/PublicAssetPicker.tsx
#	packages/frontend/src/features/swap-public/components/SolanaWalletDeposit.tsx
#	packages/frontend/src/features/swap-public/components/SwapForm.tsx
#	packages/frontend/src/features/swap-public/context/swapPublic.tsx
#	packages/frontend/src/main.tsx
#	packages/infrastructure/envs/production/main.tf
#	packages/infrastructure/envs/staging/main.tf
#	packages/infrastructure/envs/staging/staging.tfvars.local
#	packages/infrastructure/envs/staging/variables.tf
#	packages/infrastructure/modules/alb/main.tf
#	packages/infrastructure/modules/alb/variables.tf
#	packages/sdk/package.json
#	packages/sdk/src/http/api.ts
#	packages/sdk/src/http/index.ts
#	packages/sdk/src/index.ts
#	packages/sdk/src/interfaces/api.ts
#	packages/sdk/src/sdk.ts
#	packages/sdk/src/solana/index.ts
#	packages/sdk/src/types/api.ts
#	pnpm-lock.yaml
#	pnpm-workspace.yaml
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.

4 participants