Skip to content

Cart checkout fabricates transaction results: executeBatchPurchase never submits to the chain #813

Description

@nanaf6203-bit

Cart checkout fabricates transaction results: executeBatchPurchase never submits to the chain

Labels / Complexity: bug · security · High Complexity — High

Problem

The cart's checkout path does not submit a transaction. BatchTransactionService.executeBatchPurchase (src/lib/batchTransaction.ts) waits 2 seconds, rolls a Math.random() to decide success or failure, and resolves with a fabricated transactionHash:

// For now, we'll simulate a successful transaction.
try {
  return new Promise((resolve) => {
    setTimeout(() => {
      // Simulate a revert for demonstration purposes
      if (Math.random() < 0.2) {
        // ... decodeRevertReason(sampleErrorBytes) ...
        resolve({ success: false, error: reason });
      } else {
        resolve({
          success: true,
          transactionHash: `0x${[...Array(64)]
            .map(() => Math.floor(Math.random() * 16).toString(16))
            .join("")}`,
        });
      }
    }, 2000);
  });

It is wired into the real checkout UI: src/components/CartSidebar.tsx (line 52) awaits this service when the user checks out. The two TODO comments in the same file confirm the intended-but-missing behavior (// TODO: Fetch 24h price volatility to set a dynamic default slippage. and // TODO: Include slippage intent in EIP-712 typed data.). Closed issues #79 ("Feature: Batch token purchase for multiple properties", whose acceptance criteria required "Batch transaction using multicall") and #431 ("batchTransaction confirmation logic races simulation branches") are both marked COMPLETED, but the simulation is still what ships. Consequences:

  • Users see a success hash for a purchase that never happened. The token transfer, payment, and property ownership change do not occur on-chain; the UI's "confirmed" state is fiction.
  • The 20% random failure is not a real revert. Users get nondeterministic errors and fabricated revert reasons, which cannot be reproduced or debugged.
  • Funds-relevant code paths are untested against a real wallet/chain. The slippage math, EIP-712 intent, and error decoding are only ever exercised against the fake path, so the first real integration will be the first time they run.

Root cause

src/lib/batchTransaction.ts executeBatchPurchase (the setTimeout/Math.random() block, lines ~23-59). The function signature takes walletAddress and slippageTolerance but never calls a contract, never reads the wallet, and never signs.

Why this is architecturally hard

  1. The replacement must integrate the wallet layer the app already has. The app has wagmi (wagmi.config.ts), useWalletConnector, useWalletStore, and a walletStore.ts. A real batch purchase needs the connected account, a multicall contract (the app's contract ABI — check src/types/src/config for the deployed batch/multicall address), gas estimation, and a waitForTransactionReceipt flow. The contributor must decide whether the contract is a multicall or a dedicated batch-purchase contract, and where the address/config lives.
  2. The slippage math becomes real. minAmount = expectedAmount * (1 - slippageTolerance) is applied per item; with a real swap path this must match the on-chain deadline/slippage semantics and the TODO about 24h volatility, otherwise the UI's estimate and the chain's actual min-out disagree.
  3. The service API is consumed and tested. src/components/CartSidebar.tsx:52 and src/lib/__tests__/batchTransaction.test.ts both call executeBatchPurchase; the return contract (success/transactionHash/error) is reasonable, but the tests currently assert the simulation's behavior and must be rewritten against a mocked wagmi/viem client.
  4. Fake success must be impossible by construction. The current code's worst property is that the happy path needs no wallet at all. The fix must require a connected account and a real receipt before returning success: true, so a regression cannot silently re-introduce the simulation.

Downstream impact

This is the frontend's own checkout; no sibling repo changes, but the backend's transaction lifecycle (PropChain-BackEnd transactions module and test/e2e/transaction-lifecycle.e2e.spec.ts) is the server-side half a real purchase would notify — confirm the expected backend webhook/notification contract before wiring the success path.

Acceptance criteria

  • executeBatchPurchase submits a real transaction for the connected account and resolves success: true only after on-chain confirmation (receipt observed); no code path returns a fabricated hash.
  • The 20% Math.random() failure branch and the setTimeout simulation are gone.
  • The per-item slippage math is either validated against the on-chain min-out or documented as an estimate with the real values computed from the quote.
  • src/lib/__tests__/batchTransaction.test.ts is rewritten to mock wagmi/viem and assert: success returns the real hash; user rejection returns success: false with a decoded reason; disconnected wallet is rejected before any submission.
  • npm run typecheck, npm test, and npm run lint pass.

Out of scope

Dynamic volatility-based slippage (the TODO about 24h price volatility) and EIP-712 typed-data slippage intent are follow-ups; this issue is about making checkout real.

Getting started

  • src/lib/batchTransaction.ts — the simulation to replace
  • src/components/CartSidebar.tsx (line 52) — the caller
  • src/lib/__tests__/batchTransaction.test.ts — the tests to rewrite
  • src/hooks/useWalletConnector.ts, src/store/walletStore.ts, wagmi.config.ts — the wallet layer to integrate

Commands: npm run typecheck, npm test, npm run lint (scripts in package.json).

Good first files to read: src/lib/batchTransaction.ts, src/components/CartSidebar.tsx, src/hooks/useWalletConnector.ts.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

High ComplexityStellar WaveIssues in the Stellar wave programbugSomething isn't working correctlysecuritySecurity issue or hardening opportunity

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions