Skip to content

[434] [High] Oracle-Referenced Slippage and Minimum-Output Validation - #548

Merged
james2177 merged 2 commits into
stellar-vortex-protocol:mainfrom
Goodnessukaigwe:fix/434-high-oracle-referenced-slippage-and-minimum-output-validation
Sep 30, 2026
Merged

james2177 merged 2 commits into
stellar-vortex-protocol:mainfrom
Goodnessukaigwe:fix/434-high-oracle-referenced-slippage-and-minimum-output-validation

Conversation

@Goodnessukaigwe

Copy link
Copy Markdown

Summary

Intent creation now checks minDstAmount against an oracle fair destination value before the intent is stored.

  • AggregatorService builds a price snapshot from registry USD prices. validateMinDstAmount is a pure bigint function over that snapshot (USD scaled by 1e8). Fair value is floored, so it understates the destination by at most one base unit.
  • Slippage above MAX_USER_SLIPPAGE_BPS (default 100) is rejected unless acknowledgeHighSlippage is true and the user signed acknowledge-high-slippage:<user>:<srcAmount>:<minDstAmount>.
  • A minimum above fair value by more than MAX_PREMIUM_BPS (default 50) is always rejected. The exact boundary is accepted.
  • The 201 body includes fairValue (string or null) and slippageBps.
  • If the oracle is missing or older than ORACLE_MAX_STALENESS_MS (default 60s), creates at or below ORACLE_FAIL_OPEN_MAX_USD (default 100) still succeed. Larger notionals, and any create with no source price, fail closed.
  • Source and destination amounts are normalized with registry decimals, including 6/7/18 mixes. No Stellar-leg MEV protection is added.

Also restores a typechecking, bootable tree on current main: duplicate module registrations, a required-after-optional constructor, the ESM @nestjs/schedule Jest mock, and test updates for the current Stellar SDK. Those fixes are required for CI on this branch and do not change the validation rules above.

Test plan

  • npm run lint (0 errors)
  • npm run typecheck
  • npm run check:env-drift
  • npm test — 68 suites, 878 tests (passes with --maxWorkers=2; the shadow p99 budget can exceed 2ms when the full suite is heavily parallel)
  • npm run test:e2e — 28 suites, 214 tests
  • Table-driven unit tests for exact slippage/premium boundaries, acknowledgement, zero and large amounts, 6/7/18 decimals, fail-open/fail-closed, and stale snapshots
  • test/oracle-min-dst.e2e-spec.ts covers the create response metadata

Configuration

New variables, documented in every .env*.example and src/config/env.validation.ts:

Variable Default
MAX_USER_SLIPPAGE_BPS 100
MAX_PREMIUM_BPS 50
ORACLE_FAIL_OPEN_MAX_USD 100
ORACLE_MAX_STALENESS_MS 60000

No database migration.

Operational notes

See docs/adr/0003-oracle-min-dst-validation.md and the on-call runbook. Fail-open is only for small notionals when the oracle cannot produce a usable snapshot. Operators should treat a rise in ORACLE_UNAVAILABLE / STALE_ORACLE rejections as an oracle or registry price outage, not as a user-input bug.

Closes #434

Made with Cursor

Reject creates whose minimum output sits too far below or above the oracle fair destination amount, unless high slippage is explicitly signed.

Co-authored-by: Cursor <cursoragent@cursor.com>
@drips-wave

drips-wave Bot commented Sep 29, 2026

Copy link
Copy Markdown

@Goodnessukaigwe 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

…-referenced-slippage-and-minimum-output-validation

# Conflicts:
#	.env.staging.example
#	.env.testnet.example
#	CHANGELOG.md
#	docs/runbooks/on-call.md
#	jest.config.js
#	package-lock.json
#	package.json
#	src/app.module.ts
#	src/common/stellar-signature.ts
#	src/config/configuration.ts
#	src/config/env.validation.ts
#	src/governance/governance.module.ts
#	src/intents/dto/create-intent.dto.ts
#	src/intents/intents.controller.ts
#	src/intents/intents.gateway.spec.ts
#	src/intents/intents.gateway.ts
#	src/intents/intents.module.ts
#	src/intents/intents.service.shadow.spec.ts
#	src/intents/intents.service.spec.ts
#	src/intents/solver-intent-matcher.ts
#	src/intents/ws/connection-state.ts
#	src/solvers/solvers.controller.ts
#	src/soroban/event-ingestion.service.ts
#	src/soroban/signer.service.spec.ts
#	src/soroban/solver-registry.service.spec.ts
#	src/soroban/soroban.controller.spec.ts
#	src/soroban/soroban.module.ts
#	src/soroban/soroban.service.ts
#	src/soroban/stellar-tx.service.spec.ts
#	src/soroban/stellar-tx.service.ts
#	src/soroban/tx-confirmation.service.ts
#	src/tokens/in-memory-tokens.repository.ts
#	src/tokens/tokens.service.ts
#	src/treasury/treasury.service.spec.ts
#	src/treasury/treasury.service.ts
#	test/__mocks__/@stellar/stellar-sdk.ts
#	test/cors.e2e-spec.ts
#	test/dos-limits.e2e-spec.ts
#	test/jest-e2e.json
#	test/load/concurrent-accept.test.ts
#	test/load/concurrent-idempotent-create.test.ts
#	test/load/ws-broadcast-fanout.test.ts
#	test/params.e2e-spec.ts
@james2177
james2177 merged commit eedb3b8 into stellar-vortex-protocol:main Sep 30, 2026
Comment on lines +70 to +76
helmet({
contentSecurityPolicy: false,
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
frameguard: { action: "deny" },
noSniff: true,
referrerPolicy: { policy: "strict-origin-when-cross-origin" },
}),
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.

[High] Oracle-Referenced Slippage and Minimum-Output Validation

3 participants