Skip to content

fix: deterministic portfolio pricing, config reinit, registry cleanup - #611

Merged
AbelOsaretin merged 3 commits into
Heliobond:mainfrom
dunnidev:fix/portfolio-deterministic-pricing
Sep 26, 2026
Merged

AbelOsaretin merged 3 commits into
Heliobond:mainfrom
dunnidev:fix/portfolio-deterministic-pricing

Conversation

@dunnidev

@dunnidev dunnidev commented Sep 2, 2026

Copy link
Copy Markdown
Contributor
  • Replace Math.random() portfolio pricing with hour-seeded deterministic pricing via FNV-1a address hash and seededRandom (matches IoT pattern)
  • Refactor config to buildConfig() so initEnv() returns a fresh snapshot instead of the module-level singleton captured at import time
  • Move RpcDegradedError to registry.ts, remove dead isSimulationError guard
  • Fix duplicate simulateTransaction call and add missing metric tracks in getTotalProjects
  • Make MAX_PROJECT_ID configurable via env var (default 1M, was 100k)
  • Move cronTasks/scheduleCron declarations before first use
  • Harden batch score-update validation with explicit type checks
  • Update tests to align with new config/error shapes

Closes #496

- Replace Math.random() portfolio pricing with hour-seeded deterministic
  pricing via FNV-1a address hash and seededRandom (matches IoT pattern)
- Refactor config to buildConfig() so initEnv() returns a fresh snapshot
  instead of the module-level singleton captured at import time
- Move RpcDegradedError to registry.ts, remove dead isSimulationError guard
- Fix duplicate simulateTransaction call and add missing metric tracks
  in getTotalProjects
- Make MAX_PROJECT_ID configurable via env var (default 1M, was 100k)
- Move cronTasks/scheduleCron declarations before first use
- Harden batch score-update validation with explicit type checks
- Update tests to align with new config/error shapes

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@drips-wave

drips-wave Bot commented Sep 2, 2026

Copy link
Copy Markdown

@dunnidev Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

dunnidev and others added 2 commits September 24, 2026 15:26
Reconcile this branch's deterministic portfolio pricing, config-reinit and
registry-cleanup work with 112 commits of upstream changes. Keep the
branch's buildConfig()/initEnv() fresh-read refactor, the typed
simulateTransaction narrowing, and the shared anomaly history handler;
adopt upstream's MAX_PROJECT_ID contract, DB_*/IDEMPOTENCY_TTL_MS config,
the scoreService update path, and bun.lock as the sole lockfile
(package-lock.json removed).

Also fix what the resolution surfaced: duplicated imports and mocked-config
properties in several suites, and TRUST_PROXY defaulting to the string
"false" for app.set("trust proxy", ...), which made proxy-addr throw so the
server could not boot.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
CodeQL's js/insufficient-password-hash flags any fast digest applied to a
value it classifies as a password, and both inputs were run through
createHash("sha256") purely to normalise their lengths before
timingSafeEqual. The digest was only ever a length normaliser, never a
stored password hash, but the taint paths from generateApiKey(),
ADMIN_API_KEY, x-api-key and apiKeyHeader make the comparison
indistinguishable from an insecure password hash to the analysis, which
reports it as a high-severity alert on src/lib/timing-safe.ts:14.

Normalise the lengths with zero-padded fixed-size buffers instead, so no
fast digest is applied to a credential at all. The comparison stays
constant-time, never short-circuits, and both operands are still always
equal length: ordinary credentials are padded to the 512-byte window, so
neither their contents nor their length is observable. Values larger than
the window fall back to the longer of the two lengths, which stays
constant-time but reveals the order of magnitude of the longer input. The
length check is what keeps zero padding from letting "abc" collide with
"abc\u0000".

Adds coverage for that collision and for values past the window.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@AbelOsaretin
AbelOsaretin merged commit def0310 into Heliobond:main Sep 26, 2026
3 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.

GET /v1/portfolio/:address returns a different current_value on every call — pricePerShare uses raw Math.random()

2 participants