Skip to content

fix(keeper): require USE_HELIUS_SENDER=true on mainnet - #364

Open
Morenikeoa wants to merge 1 commit into
dcccrypto:mainfrom
Morenikeoa:fix/mainnet-require-helius-sender
Open

fix(keeper): require USE_HELIUS_SENDER=true on mainnet#364
Morenikeoa wants to merge 1 commit into
dcccrypto:mainfrom
Morenikeoa:fix/mainnet-require-helius-sender

Conversation

@Morenikeoa

Copy link
Copy Markdown
Contributor

Problem

isMainnetSender() in src/lib/keeper-send.ts is a literal USE_HELIUS_SENDER === "true" check with no NETWORK-based default:

function isMainnetSender(): boolean {
  return (
    isMainnetNetwork(process.env.NETWORK) &&
    process.env.USE_HELIUS_SENDER === "true"
  );
}

When USE_HELIUS_SENDER is unset or any non-"true" value, the keeper silently falls back to plain sendRawTransaction broadcast (skipPreflight: true, no Jito bundle) to public RPCs. This exposes the liquidation target pubkey and close size to any RPC operator or mempool listener before confirmation — enabling front-running/sandwiching, or outright liquidation-sniping (a third party copying the observed instruction with their own fee payer to capture the liquidation incentive).

.env.example documents USE_HELIUS_SENDER=true as the recommended mainnet default, but nothing in code enforces it. A deployment built from a partial/incomplete env (not copying that line, or built directly from Railway env vars without referencing .env.example) degrades silently with zero boot-time signal — unlike every other mainnet-critical setting already guarded in env-guards.ts (DISCORD_ALERT_WEBHOOK, KEEPER_REDIS_URL/KEEPER_REDIS_TOKEN, RPC URL scheme/host checks).

Production Impact

On mainnet, with USE_HELIUS_SENDER unset (a plausible operator mistake given it's optional in code), every liquidation and crank transaction broadcasts to public RPCs pre-confirmation with no MEV protection. A searcher watching the keeper's known fee-payer pubkey can observe a pending liquidation instruction and either sandwich it or race a copy of it with a higher fee, stealing the liquidation reward. This is a silent degradation — the keeper runs and appears healthy with no indication that it's operating without its intended MEV protection.

Fix

Add a boot-time guard in validateKeeperEnvGuards() requiring USE_HELIUS_SENDER=true when NETWORK=mainnet, mirroring the existing DISCORD_ALERT_WEBHOOK (H-7) fail-loud pattern. Off mainnet (devnet/local dev), the setting remains optional as before.

Proof of Fix

New tests in tests/env-guards.test.ts (BUG-101: USE_HELIUS_SENDER required on mainnet):

  • Throws when unset on mainnet
  • Throws when "false" on mainnet
  • Throws when an arbitrary non-"true" string on mainnet
  • Accepts "true" on mainnet
  • Does not require it off mainnet

Existing mainnet-accepting test fixtures elsewhere in the file were updated to include USE_HELIUS_SENDER: "true" so they continue to exercise the happy path correctly.

Test Output

 Test Files  1 failed | 93 passed | 2 skipped (96)
      Tests  1 failed | 979 passed | 33 skipped (1013)

The one failure (tests/v17-risk-params.poc.test.ts) is pre-existing and unrelated to this change — a stale assertion left over from commit 8ee810d (#345), which changed production code to accept maintenanceMarginBps==10000 but didn't update that older PoC test. Confirmed unrelated by file scope (no overlap with env-guards.ts/keeper-send.ts).

pnpm build — clean, zero errors.

isMainnetSender() in keeper-send.ts is a literal `USE_HELIUS_SENDER === "true"`
check with no NETWORK-based default. When unset or any non-"true" value, the
keeper silently falls back to plain sendRawTransaction broadcast (skipPreflight,
no Jito bundle) to public RPCs, exposing the liquidation target pubkey and close
size to any RPC operator or mempool listener before confirmation -- enabling
front-running/sandwiching or outright liquidation-sniping (a third party copying
the observed instruction with their own fee payer).

.env.example documents USE_HELIUS_SENDER=true as the mainnet default, but
nothing enforced it -- a deployment built from a partial env degraded silently
with zero boot-time signal, unlike every other mainnet-critical setting in
env-guards.ts (DISCORD_ALERT_WEBHOOK, KEEPER_REDIS_URL, RPC URL scheme/host
guards). This mirrors that existing fail-loud-on-mainnet pattern.

BUG-101 from a clean-room Phase 4 audit pass.
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Morenikeoa, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 33 minutes and 32 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a6ce9f10-3624-4a98-9cfd-5bf4950c1000

📥 Commits

Reviewing files that changed from the base of the PR and between 8ee810d and b12cdec.

📒 Files selected for processing (2)
  • src/env-guards.ts
  • tests/env-guards.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

1 participant