Skip to content

fix(managed-wallet): block lease creation on absurdly-overpriced bids#3341

Draft
baktun14 wants to merge 3 commits into
mainfrom
fix/billing-block-overpriced-lease-bids
Draft

fix(managed-wallet): block lease creation on absurdly-overpriced bids#3341
baktun14 wants to merge 3 commits into
mainfrom
fix/billing-block-overpriced-lease-bids

Conversation

@baktun14

@baktun14 baktun14 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Why

Managed-wallet lease creation accepted the winning bid without validating its price-per-block. This
adds a guardrail so an abnormally-priced bid is refused before the lease is created, with alerting
for visibility.

Fixes CON-554

What

Server-side price guardrail in the managed-wallet lease-creation path, evaluated before the
transaction is broadcast:

  • Relative check — refuse when the accepted bid is far above the cheapest competing bid for the
    same order; warn-only (logged, not blocked) in a configurable band below the block threshold.
  • Absolute ceiling — optional per-denom maximum as a backstop when there is no competing bid to
    compare against.
  • Alerting — structured log when a bid is refused or flagged.
  • Config — thresholds under MANAGED_WALLET_BID_PRICE_*, enabled by default with a kill-switch.
  • Scope: managed/custodial wallets only (self-custodial users sign their own transactions).

Tests

Unit coverage for the guard (relative / absolute / warn / allow, sole-bidder, disabled, multi-order,
unresolved bid) plus a managed-signer wiring test ensuring a refused bid never reaches broadcast.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a managed-wallet lease bid price guard that validates lease bid pricing before lease broadcasting.
    • Introduced configurable relative warning/block thresholds based on competing bids within the same deployment order.
    • Added optional per-denomination absolute maximum price ceilings for added protection.
  • Bug Fixes

    • Improved lease bid resolution and validation consistency to ensure incorrect or mismatched referenced bids are correctly rejected.
  • Tests

    • Added comprehensive guard and signer flow coverage, including blocking behavior and 403 error handling.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a626b245-90e8-4cf2-a711-83643525190d

📥 Commits

Reviewing files that changed from the base of the PR and between fc31e75 and 2a1bc23.

📒 Files selected for processing (3)
  • apps/api/src/billing/config/env.config.ts
  • apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.spec.ts
  • apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.ts
💤 Files with no reviewable changes (1)
  • apps/api/src/billing/config/env.config.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.ts
  • apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.spec.ts

📝 Walkthrough

Walkthrough

Adds LeaseBidPriceGuardService, a new singleton guard that validates managed-wallet lease bid prices against relative peer-based multipliers and denom-specific absolute ceilings before broadcast. Shared bid-resolution helpers (getLeaseBidIds, resolveLeaseBids) are extracted into a new library file and consumed by both the guard and a refactored TrialValidationService. Five new env config fields control guard behavior.

Changes

Managed-Wallet Lease Bid Price Guard

Layer / File(s) Summary
Env config and shared bid-resolution contracts
apps/api/src/billing/config/env.config.ts, apps/api/src/billing/lib/lease-messages/lease-messages.ts
Adds five env schema fields (MANAGED_WALLET_BID_PRICE_GUARD_ENABLED, warn/block multipliers, two optional absolute max fields) with schema-level validation; defines LeaseBidId type and ResolvedLeaseBid interface.
Shared lease-bid resolution helpers
apps/api/src/billing/lib/lease-messages/lease-messages.ts
Implements getLeaseBidIds (filters MsgCreateLease messages and extracts bid IDs) and resolveLeaseBids (parallel dseq-batched bid fetching via HTTP service; throws 403 on missing accepted bid).
LeaseBidPriceGuardService implementation
apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.ts
Full guard implementation: resolves bids, applies relative peer-based block/warn checks using BLOCK_MULTIPLIER and WARN_MULTIPLIER, applies denom-specific absolute ceiling checks via #getAbsoluteMax, logs LEASE_BLOCKED_EXCESSIVE_BID_PRICE error events, and throws 403 on violations.
LeaseBidPriceGuardService tests
apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.spec.ts
Comprehensive Vitest suite covering relative/absolute check branches, guard-disabled no-op, bid-resolution failures (missing bid, owner mismatch), and multi-order independent evaluation; includes bid/message builder helpers and wired setup.
ManagedSignerService wiring
apps/api/src/billing/services/managed-signer/managed-signer.service.ts, ...service.spec.ts
Injects LeaseBidPriceGuardService dependency, calls validateLeaseBidPrices(messages, userWallet) in executeDecodedTxByUserWallet after existing GPU validations. Test confirms overpriced leases are rejected with 403 and broadcast is not invoked.
TrialValidationService refactor
apps/api/src/billing/services/trial-validation/trial-validation.service.ts, ...service.spec.ts
Removes private getLeaseBidIds helper and inline bid-fetch/match logic; delegates to shared getLeaseBidIds and resolveLeaseBids utilities in both validateLeaseProvidersAuditors and validateLeaseGpuModels. GPU-model blocking behavior preserved. Test helper updated to explicitly wire bid owner.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • akash-network/console#3198: Modifies validateLeaseGpuModels in TrialValidationService—the same method this PR refactors to use shared resolveLeaseBids.

Suggested reviewers

  • ygrishajev
  • stalniy
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/billing-block-overpriced-lease-bids

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

@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.73418% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 68.28%. Comparing base (f62370e) to head (2a1bc23).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
apps/api/src/billing/config/env.config.ts 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3341      +/-   ##
==========================================
- Coverage   69.60%   68.28%   -1.32%     
==========================================
  Files        1087     1000      -87     
  Lines       26669    24415    -2254     
  Branches     6415     5971     -444     
==========================================
- Hits        18562    16671    -1891     
+ Misses       7110     6779     -331     
+ Partials      997      965      -32     
Flag Coverage Δ *Carryforward flag
api 84.96% <98.73%> (+0.09%) ⬆️
deploy-web 55.25% <ø> (ø) Carriedforward from fc31e75
log-collector ?
notifications 91.44% <ø> (ø) Carriedforward from fc31e75
provider-console 81.38% <ø> (ø) Carriedforward from fc31e75
provider-inventory ?
provider-proxy 86.26% <ø> (ø) Carriedforward from fc31e75
tx-signer ?

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
...i/src/billing/lib/lease-messages/lease-messages.ts 100.00% <100.00%> (ø)
...e-bid-price-guard/lease-bid-price-guard.service.ts 100.00% <100.00%> (ø)
.../services/managed-signer/managed-signer.service.ts 100.00% <100.00%> (ø)
...vices/trial-validation/trial-validation.service.ts 56.25% <100.00%> (-8.75%) ⬇️
apps/api/src/billing/config/env.config.ts 90.00% <88.88%> (+2.50%) ⬆️

... and 89 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.spec.ts (1)

20-145: ⚡ Quick win

Add a precision-boundary test case for very large amounts.

Given this guard’s security role, add at least one test around Number.MAX_SAFE_INTEGER-scale amounts to ensure warn/block decisions remain correct at high values and prevent regressions in threshold math.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.spec.ts`
around lines 20 - 145, Add a new test case within the "relative limit" describe
block that validates warn/block behavior with amounts near
Number.MAX_SAFE_INTEGER scale. The test should use pricedBid to create bids with
very large numbers (similar to the existing 9_519_658 patterns but significantly
larger, approaching MAX_SAFE_INTEGER thresholds) and verify that the service
correctly applies the warn and block multiplier thresholds at these precision
boundaries. This ensures threshold math calculations remain accurate with
extreme values and prevents future regressions in the bid price comparison
logic, particularly for the ratio calculations used in the relative limit
checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/billing/config/env.config.ts`:
- Around line 59-60: The schema currently validates
MANAGED_WALLET_BID_PRICE_WARN_MULTIPLIER and
MANAGED_WALLET_BID_PRICE_BLOCK_MULTIPLIER independently as positive numbers,
which allows the warn multiplier to exceed the block multiplier and break the
intended warn-before-block behavior. Add a cross-field validation constraint
using Zod's refine method on the schema object to ensure that
MANAGED_WALLET_BID_PRICE_WARN_MULTIPLIER is always less than or equal to
MANAGED_WALLET_BID_PRICE_BLOCK_MULTIPLIER, with an appropriate error message
describing the constraint violation.

In `@apps/api/src/billing/lib/lease-messages/lease-messages.ts`:
- Around line 52-54: The find predicate used to locate the accepted bid in the
orderBids array is missing the owner field from the identity comparison. The
predicate currently checks gseq, oseq, provider, and bseq but omits bidId.owner,
which is part of the bid identity key. Add b.bid.id.owner === bidId.owner to the
find predicate alongside the existing identity field comparisons to ensure the
accepted bid is correctly matched using the complete identity.

In
`@apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.ts`:
- Around line 52-55: Replace the `Number()` conversion of
`accepted.bid.price.amount` with `BigInt()` to preserve precision for large
blockchain integers that exceed JavaScript's safe integer range. Update the
validation check for `acceptedPrice` to work with BigInt comparisons instead of
Number comparisons. Additionally, ensure that the peer prices and all threshold
ratio checks at lines 72-77 also use BigInt arithmetic instead of numeric
arithmetic to maintain consistency and prevent precision loss in these
security-critical bid validation comparisons.

---

Nitpick comments:
In
`@apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.spec.ts`:
- Around line 20-145: Add a new test case within the "relative limit" describe
block that validates warn/block behavior with amounts near
Number.MAX_SAFE_INTEGER scale. The test should use pricedBid to create bids with
very large numbers (similar to the existing 9_519_658 patterns but significantly
larger, approaching MAX_SAFE_INTEGER thresholds) and verify that the service
correctly applies the warn and block multiplier thresholds at these precision
boundaries. This ensures threshold math calculations remain accurate with
extreme values and prevents future regressions in the bid price comparison
logic, particularly for the ratio calculations used in the relative limit
checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 06b24255-fe6d-46c0-9887-8346368de292

📥 Commits

Reviewing files that changed from the base of the PR and between f62370e and b06ef17.

📒 Files selected for processing (7)
  • apps/api/src/billing/config/env.config.ts
  • apps/api/src/billing/lib/lease-messages/lease-messages.ts
  • apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.spec.ts
  • apps/api/src/billing/services/lease-bid-price-guard/lease-bid-price-guard.service.ts
  • apps/api/src/billing/services/managed-signer/managed-signer.service.spec.ts
  • apps/api/src/billing/services/managed-signer/managed-signer.service.ts
  • apps/api/src/billing/services/trial-validation/trial-validation.service.ts

Comment thread apps/api/src/billing/config/env.config.ts Outdated
Comment thread apps/api/src/billing/lib/lease-messages/lease-messages.ts
@github-actions github-actions Bot added size: L and removed size: M labels Jun 20, 2026
baktun14 added 2 commits June 20, 2026 16:07
Managed-wallet lease creation accepted the winning bid without validating its
price-per-block. Add a server-side guardrail (LeaseBidPriceGuardService) in the
managed-signer validation block: it refetches the order's bids and refuses leases
whose price-per-block is far above the cheapest competing bid for the same order,
with an absolute per-denom ceiling for the sole-bidder case. Moderately-high prices
are allowed but logged at warn; blocks emit a structured error log. All thresholds
are configurable and the guard can be disabled.

Extracts shared bid resolution into lease-messages.ts, reused by trial validation.
Address review: validate WARN_MULTIPLIER <= BLOCK_MULTIPLIER in the config schema so a
misconfiguration can't silently disable the warn tier, and include the deployment owner in the
accepted-bid match so a lease referencing a foreign owner is rejected.
@baktun14 baktun14 force-pushed the fix/billing-block-overpriced-lease-bids branch from 28bcf57 to fc31e75 Compare June 20, 2026 20:07
Deployments are uact-denominated, so the per-denom absolute ceiling only needs uact. Remove
the unused UAKT config key and the uakt branch; the relative check is denom-agnostic and
unaffected. A non-uact bid simply has no absolute cap and relies on the relative check.
const { id } = accepted.bid;

// Cheapest bid for the same order (gseq + oseq). Needs at least one competing bid to be meaningful.
const peerPrices = orderBids

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: can be achieved with Iterator.from(orderBids) more efficiently

* Two checks:
* - Relative: block when the accepted bid is far above the cheapest competing bid for the same
* order (apples-to-apples — same resources, denom and moment). Only applied when peers exist.
* - Absolute: block when the per-block price exceeds a configured per-denom ceiling. Covers the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: overloaded term "block" - block when per-block hard to reason about. probably you wanted to say reject when the per-block...

);
}

#block(reason: "relative" | "absolute", accepted: Bid, userWallet: UserWalletOutput, details: Record<string, unknown>, message: string): never {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

**suggestion: ** rename to forbid or reject

@baktun14 baktun14 marked this pull request as draft June 23, 2026 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants