Skip to content

feat: harden concurrent buys, wallet balance, challenge timing, and p… - #531

Merged
barry01-hash merged 3 commits into
PromptMintLabs:mainfrom
ExcelDsigN-tech:feat/concurrent-buys-and-payload-hardening
Aug 30, 2026
Merged

feat: harden concurrent buys, wallet balance, challenge timing, and p…#531
barry01-hash merged 3 commits into
PromptMintLabs:mainfrom
ExcelDsigN-tech:feat/concurrent-buys-and-payload-hardening

Conversation

@ExcelDsigN-tech

Copy link
Copy Markdown

feat: harden concurrent buys, wallet balance, challenge timing, and payload limits

Closes #510, Closes #511, Closes #512, Closes #513

Overview

Hardens 4 critical reliability and security paths in the prompt-hash contract and API subsystem to address race conditions, timing side-channels, cryptic transaction errors, and silent payload storage limit violations.

Feature Summary

  • Prevented concurrent buy/lease oversells by moving max_supply checks and sales_count increments into an atomic step before token transfers
  • Mapped raw Soroban op_underfunded / token errors to a structured InsufficientBalance contract error and user-friendly client message
  • Mitigated wallet enumeration timing attacks in the authentication challenge endpoint by executing a constant-time dummy HMAC calculation on invalid inputs
  • Surfaced structured PAYLOAD_TOO_LARGE errors when encrypted prompt payloads exceed the 4096-character contract limit
  • Added 5 contract regression tests covering wallet funding guards and atomic supply enforcement

Technical Implementation

  • Concurrent Buys & Atomic State Updates (contracts/prompt-hash/contract.rs):
    • Updated execute_buy, buy_bundle, and lease_prompt to check max_supply, increment sales_count, and invoke Storage::update_prompt immediately after setting the reentrancy guard and before initiating any transfer_from operations
    • Removed duplicate post-transfer increments and redundant pre-validation checks
  • Wallet Balance Verification (contracts/prompt-hash/types.rs, contract.rs, promptHashClient.ts):
    • Added InsufficientBalance = 55 to the Error enum
    • Added explicit asset_client.balance(&buyer) pre-checks with ensure!(balance >= price, InsufficientBalance) prior to calling transfer_from across all purchase and lease flows
    • Extended CONTRACT_ERROR_CODES and classifyContractError in promptHashClient.ts to translate InsufficientBalance and op_underfunded into WALLET_NOT_FUNDED and INSUFFICIENT_BALANCE
  • Timing Side-Channel Prevention (api/auth/challenge.ts):
    • Added dummy createHmac("sha256", secret).update("padding").digest("base64url") processing on parseRequestBody failures to normalize response latency across valid and invalid inputs
  • Error Codes & Payload Validation (src/lib/api/errorCodes.ts):
    • Added PAYLOAD_TOO_LARGE and WALLET_NOT_FUNDED variants with user-actionable error messages

Test Coverage

  • Added 5 contract tests in contracts/prompt-hash/src/test.rs:
    • test_buy_returns_insufficient_balance_when_wallet_unfunded
    • test_buy_supply_enforcement_is_atomic
    • test_buy_bundle_returns_insufficient_balance_when_wallet_unfunded
    • test_buy_bundle_supply_enforcement_blocks_when_full
    • test_lease_returns_insufficient_balance_when_wallet_unfunded
  • Added timing/enumeration coverage test in api/auth/challenge.test.ts verifying identical 400 MISSING_FIELDS responses across invalid addresses
  • Note: Full cargo test and vitest suite runs pending CI execution under Rust 1.91+ toolchain and installed dependency tree

Checklists

  • Make max_supply check and sales_count increment atomic before token transfers
  • Pre-check buyer asset balance and throw InsufficientBalance (Error 55) on underfunded wallets
  • Normalize challenge handler execution timing for invalid requests via dummy HMAC execution
  • Add client-side error code mapping for INSUFFICIENT_BALANCE and PAYLOAD_TOO_LARGE
  • Retain input body size limits and secret length guards across API routes
  • Add contract tests for atomic supply enforcement and unfunded wallet handling

…ayload limits

- contract: add InsufficientBalance (55) and atomic max_supply check+increment+write immediately after reentrancy guard in execute_buy, buy_bundle, and lease_prompt to prevent concurrent oversell
- contract: pre-check asset_client.balance before transfer_from to surface clear InsufficientBalance instead of raw Soroban op_underfunded
- api: normalize challenge endpoint timing with dummy HMAC on validation failure to prevent wallet enumeration
- api: add PAYLOAD_TOO_LARGE and WALLET_NOT_FUNDED error codes and map contract errors in promptHashClient (InsufficientBalance/op_underfunded, InvalidFieldLength)
- tests: add 5 contract tests for supply enforcement and insufficient balance, and challenge enumeration test
@drips-wave

drips-wave Bot commented Aug 28, 2026

Copy link
Copy Markdown

@ExcelDsigN-tech 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

ExcelDsigN-tech added 2 commits August 28, 2026 19:42
- contracts/types.rs: remove stray PromptExpiryWarning(u128) from PriceHistoryEntry struct (98943397248)
- workflows/security-pentest.yml: chmod 777 reports before ZAP scan (98943398022)
- workflows/soroban-schema-validation.yml: add corepack enable before yarn (98943397019)
- postcss.config.js: use @tailwindcss/postcss for Tailwind v4 (98943397042) and add devDep
- package.json: downgrade stellar-wallets-kit 2.5.0 -> 1.9.5 to restore WalletNetwork/ALBEDO_ID/allowAllModules API (98943396889) and add @tailwindcss/postcss
- api/auth/rotateSecret.ts: remove duplicate auth check missing brace (98943396564)
- api/moderation/logs.ts: add missing return after 403 (98943396564)
- api/prompts/unlock.test.ts: add missing } after MISSING_FIELDS test (98943396564)
- api/prompts/unlock.ts: collapse duplicate integrity blocks and fix missing } / duplicate res.json before catch (98943396564)
- src/components/SearchBar.tsx: relax eslint-disable rule to avoid missing plugin (98943396564)
@barry01-hash
barry01-hash merged commit 914d6b9 into PromptMintLabs:main Aug 30, 2026
4 of 15 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

2 participants