Skip to content

fix(fees): verify single-use payment before fee-bump signing - #1539

Merged
greatest0fallt1me merged 2 commits into
CalloraOrg:mainfrom
TMTOFFUTA:fix/issue-1495-verify-the-app-token-payment-before-signing-fee
Oct 21, 2026
Merged

greatest0fallt1me merged 2 commits into
CalloraOrg:mainfrom
TMTOFFUTA:fix/issue-1495-verify-the-app-token-payment-before-signing-fee

Conversation

@TMTOFFUTA

Copy link
Copy Markdown

Overview

This PR hardens POST /api/billing/fee-abstraction so that the platform's fee account can no longer be drained by any authenticated user. It introduces signed, single-use quotes persisted in a new fee_abstraction_quotes table, verifies the app-token payment on-chain before any fee-bump is signed, enforces an inner-transaction policy (hash, source, allowlisted operations), computes Soroban-aware fees in integer stroops, and makes the app-token rate configurable. The execute route is placed behind the existing idempotency middleware.

Related Issue

Changes

🔒 Fee Abstraction Hardening

  • [MODIFY] prisma/schema.prisma

    • Adds the FeeAbstractionQuote model backing the new fee_abstraction_quotes table: user id, innerTxHash, fee in stroops (bigint), app-token amount (integer units), status, expiresAt, and the consumed payment id.
    • Unique constraint on the payment id so a single payment can back at most one fee-bump, enforced at the database level.
  • [ADD] migrations/0027_fee_abstraction_quotes.sql

    • Creates the fee_abstraction_quotes table with the unique payment-id constraint and indexes needed by the quote/execute flow.
  • [MODIFY] src/config/env.ts

    • Replaces the hard-coded XLM_TO_APP_TOKEN_RATE = 0.10 with configurable FEE_ABSTRACTION_RATE_* settings, integer-scaled so no float math is used for amounts.
  • [MODIFY] src/services/feeBumper.ts

    • calculateFeeQuote now adds the inner transaction's sorobanData.resourceFee to baseFeeStroops × (ops + 1) × multiplier, all in bigint.
    • createFeeBumpTransaction is only reachable after the caller has verified the quote and payment; it no longer signs arbitrary XDR on its own.

🧪 Verification

  • npm run db:check-migrations — passes with the new migration.
  • npm run lint, npm run typecheck, npm run build, npm test — expected green in CI.
  • Targeted run: npm run test:unit -- src/routes/billing/feeAbstraction src/services/feeBumper.

Threat Model & Double-Spend Prevention

  • Threat: any authenticated user submits an arbitrary inner XDR plus a bogus appTokenPaymentTxId and gets the platform to pay network fees.
  • Mitigation: a fee-bump is only signed when (a) a persisted, unexpired quote exists for the authenticated user, (b) the inner transaction hash matches the quoted hash, (c) the inner source is the user's Stellar address, (d) the operations are on the allowlist (invokeHostFunction targeting the configured vault contract ids), and (e) the on-chain payment is successful, from the user's address, created after the quote, and transfers at least the quoted app-token amount to the treasury.
  • Double-spend prevention: the quote is marked consumed in the same transaction that records the payment id, and a unique constraint on the payment id guarantees one payment backs at most one fee-bump. Reuse returns 409 even under concurrent requests, because the constraint — not application logic alone — is the final gate.
  • Fail-closed: payment verification is bounded by the route timeout; timeouts and lookup failures result in no signature.
Acceptance Criteria Status
Fee-bumps only signed for verified, unconsumed quotes ✅ Quote + payment verification gate all signing
npm run db:check-migrations passes ✅ New migration added
Lint / typecheck / build / test pass, CI green ⏳ Pending CI
≥90% line coverage on feeBumper.ts and feeAbstraction.ts ⏳ Pending coverage run
Error codes regenerated and OpenAPI updated ⏳ Follow-up in this PR

Closes #1495

@drips-wave

drips-wave Bot commented Oct 20, 2026

Copy link
Copy Markdown

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

@greatest0fallt1me
greatest0fallt1me merged commit 77c6c5f into CalloraOrg:main Oct 21, 2026
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.

Verify the app-token payment before signing fee-bump transactions in /api/billing/fee-abstraction

2 participants