From 23d9bb55d17a0f978c4716d773e5a983d0529e8a Mon Sep 17 00:00:00 2001 From: Adiz4415 Date: Sat, 20 Jun 2026 12:21:35 +0000 Subject: [PATCH 01/11] [Fix #12] Consolidate ACBU smart contracts known-issues catalog - Restructure PROJECT/issues/CONTRACTS_ISSUES.md into a single source of truth using canonical severity/area/evidence/impact/fix/acceptance format. - Cover all 60 catalog entries from issues/contracts.md (Critical 6, High 21, Medium 24, Low 9) with stable C-### IDs. - Preserve the legacy 34-item list as Section 7 cross-reference. - Add Summary Table, Severity Counts, Resolution Tracker, Top Remediations (ship-safety order), Cross-Reference Map, and Maintenance notes. - Provide anchor points for future PR references. Closes #12 --- PROJECT/issues/CONTRACTS_ISSUES.md | 698 +++++++++++++++++++++++++++-- 1 file changed, 657 insertions(+), 41 deletions(-) diff --git a/PROJECT/issues/CONTRACTS_ISSUES.md b/PROJECT/issues/CONTRACTS_ISSUES.md index e4e5d83..d495a83 100644 --- a/PROJECT/issues/CONTRACTS_ISSUES.md +++ b/PROJECT/issues/CONTRACTS_ISSUES.md @@ -1,54 +1,670 @@ -# Contracts – Known Issues +# Smart Contracts — Known Issues -Issues found in the smart contracts (acbu_minting, acbu_burning, acbu_oracle, acbu_reserve_tracker, acbu_savings_vault, acbu_lending_pool, acbu_escrow, shared). Add new items below as numbered list entries. +This document is the **single source of truth** for known issues in the ACBU Soroban smart contracts (`acbu_minting`, `acbu_burning`, `acbu_oracle`, `acbu_reserve_tracker`, `acbu_savings_vault`, `acbu_lending_pool`, `acbu_escrow`, plus the `shared` crate). + +> **How to use** +> +> - Each issue is structured as: **severity · area · evidence · impact · fix direction · acceptance check**. +> - Issues are ordered by severity, then by ID for stable cross-referencing. +> - Provenance: this file consolidates the legacy 34-item list previously at `PROJECT/issues/CONTRACTS_ISSUES.md` and the canonical 60-item catalog at `issues/contracts.md` into one document. Tracking duplicates the working catalog (`issues/contracts.md`) which remains the live triage-ready list; this file is the durable long-form reference. +> - When an item is fixed, prefer **linking the PR** in your tracker and removing the entry here rather than rewriting history. +> - **Severity legend:** 🔴 Critical · 🟠 High · 🟡 Medium · 🟢 Low · ⚪ Trivial + +--- + +## 1. Summary Table + +| ID | Severity | Area | Contract / Crate | Title | +|----|----------|------|------------------|-------| +| C-001 | 🔴 Critical | contracts/escrow | `acbu_escrow` | `release` missing authorization | +| C-002 | 🔴 Critical | contracts/minting | `acbu_minting` | `mint_from_fiat` lacks off-chain settlement proof | +| C-003 | 🔴 Critical | contracts/escrow | `acbu_escrow` | Escrow ID key collision | +| C-004 | 🔴 Critical | contracts/reserves | `acbu_reserve_tracker` | `verify_reserves` uses wrong supply source | +| C-005 | 🔴 Critical | contracts/savings | `acbu_savings_vault` | Missing `require_auth` on deposit/withdraw | +| C-006 | 🔴 Critical | contracts/lending | `acbu_lending_pool` | Missing `require_auth` on deposit/withdraw | +| C-007 | 🟠 High | contracts/savings | `acbu_savings_vault` | Term not enforced | +| C-008 | 🟠 High | contracts/minting | `acbu_minting` | `mint_from_fiat` missing max mint bound | +| C-009 | 🟠 High | contracts/burning | `acbu_burning` | Burn basket integer division dust loss | +| C-010 | 🟠 High | contracts/escrow | `acbu_escrow` | Escrow create lacks duplicate guard | +| C-011 | 🟠 High | contracts/minting | `acbu_minting` | Oracle/reserve clients loaded but not called | +| C-012 | 🟠 High | contracts/burning | `acbu_burning` | Oracle/reserve clients loaded but not called | +| C-021 | 🟠 High | contracts/integration | All | Event payload schema drift vs backend listeners | +| C-027 | 🟠 High | contracts/lending | `acbu_lending_pool` | Loan events never emitted / loan logic missing | +| C-028 | 🟠 High | contracts/qa | `acbu_minting/tests` | Missing tests for core mint flows | +| C-034 | 🟠 High | contracts/ops | Multiple | No contract versioning / upgrade story | +| C-035 | 🟠 High | contracts/governance | Mint/burn/savings/lending | Admin pause flags not verified on all state changes | +| C-037 | 🟠 High | contracts/security | All `*_amount` fields | Integer overflow review for all i128 money math | +| C-038 | 🟠 High | contracts/security | Mint/burn | Authorization invocation tree for cross-contract calls | +| C-039 | 🟠 High | contracts/minting | `acbu_minting` | Strict input validation for string IDs | +| C-040 | 🟠 High | contracts/tokenomics | Mint/burn/oracle | Decimal scaling consistency (7 decimals) | +| C-041 | 🟠 High | contracts/oracle | `acbu_oracle` | Staleness: max ledger age for rates | +| C-042 | 🟠 High | contracts/oracle | `acbu_oracle` | Minimum oracle sources for quorum | +| C-050 | 🟠 High | contracts/qa | `acbu_escrow/tests` | Integration tests: escrow full lifecycle | +| C-051 | 🟠 High | contracts/qa | `acbu_savings_vault/tests` | Integration tests: savings lock + interest | +| C-052 | 🟠 High | contracts/qa | `acbu_lending_pool/tests` | Integration tests: lending borrow/repay | +| C-055 | 🟠 High | contracts/authz | `acbu_minting` and others | Access control naming audit (`check_admin_or_user`) | +| C-013 | 🟡 Medium | contracts/build | Mint/burn/reserve tracker | Token WASM import uses zero SHA256 placeholder | +| C-014 | 🟡 Medium | contracts/escrow | `acbu_escrow` | Double `.unwrap().unwrap()` pattern in storage reads | +| C-015 | 🟡 Medium | contracts/savings | `acbu_savings_vault` | Double `.unwrap().unwrap()` pattern | +| C-016 | 🟡 Medium | contracts/lending | `acbu_lending_pool` | Double `.unwrap().unwrap()` pattern | +| C-017 | 🟡 Medium | contracts/oracle | `acbu_oracle` | Outlier detection is a no-op | +| C-018 | 🟡 Medium | contracts/oracle | `acbu_oracle/tests` | Oracle unit test assertion incorrect vs median behavior | +| C-020 | 🟡 Medium | contracts/shared | `shared` | `median` allocates via `to_vec()` in shared util | +| C-024 | 🟡 Medium | contracts/savings | `acbu_savings_vault` | Savings withdraw yield always zero | +| C-025 | 🟡 Medium | contracts/lending | `acbu_lending_pool` | Lending fee rate unused | +| C-026 | 🟡 Medium | contracts/savings | `acbu_savings_vault` | Savings fee rate unused | +| C-032 | 🟡 Medium | contracts/minting | `acbu_minting` | Predictable `transaction_id` in minting | +| C-033 | 🟡 Medium | contracts/reserves | `acbu_reserve_tracker` | Reserve tracker emits no events on updates | +| C-036 | 🟡 Medium | contracts/security | Token transfers inside contracts | Reentrancy class issues via token callbacks | +| C-043 | 🟡 Medium | contracts/governance | Admin-only methods | Emergency multisig for admin operations | +| C-044 | 🟡 Medium | contracts/qa | CI pipeline | Contract size/compute budget regression tests | +| C-046 | 🟡 Medium | contracts/security | Rust dependencies | `cargo audit` / supply chain monitoring | +| C-047 | 🟡 Medium | contracts/docs | `INTEGRATION.md` / `SMART_CONTRACT_SPEC` | Formalize invariants documentation per contract | +| C-048 | 🟡 Medium | contracts/ops | `dummy_token` etc. | Testnet vs mainnet feature flags in code | +| C-054 | 🟡 Medium | contracts/api-ux | All contracts | Consistent error codes for clients | +| C-056 | 🟡 Medium | contracts/token | Mint/burn pulling user tokens | Token allowance assumptions | +| C-057 | 🟡 Medium | contracts/burning | `acbu_burning` `burn_for_basket` | Validate recipient accounts non-empty + distinct | +| C-058 | 🟡 Medium | contracts/minting | Recipient address parameter | Mint path: validate recipient is a real account | +| C-059 | 🟡 Medium | contracts/reserves | `acbu_reserve_tracker` init | Initialization parameters validation | +| C-060 | 🟡 Medium | contracts/ops | `acbu_oracle` admin | Oracle admin rotation workflow | +| C-019 | 🟢 Low | contracts/burning | `acbu_burning` | Redundant DECIMALS multiply/divide in burn path | +| C-022 | 🟢 Low | contracts/fees | `acbu_savings_vault`, `acbu_lending_pool` | Magic number vs `BASIS_POINTS` constant inconsistency | +| C-023 | 🟢 Low | contracts/burning | `acbu_burning` events | Per-account BurnEvent fee reporting mismatch | +| C-029 | 🟢 Low | contracts/hygiene | `acbu_minting` | Unused import noise in minting crate | +| C-030 | 🟢 Low | contracts/burning | `acbu_burning` | Empty recipient list style / checks | +| C-031 | 🟢 Low | contracts/oracle | `acbu_oracle` | Oracle RateUpdateEvent validators empty | +| C-045 | 🟢 Low | contracts/devx | `acbu-smart-contract/Cargo.lock` | Deterministic builds: `Cargo.lock` policy | +| C-049 | 🟢 Low | contracts/build | Root `soroban_token_contract.wasm` | Wasm artifact in repo | +| C-053 | 🟢 Low | contracts/perf | Events with large vectors | Gas griefing: unbounded vectors in events | + +**Totals:** 6 Critical · 21 High · 24 Medium · 9 Low · **60 total catalog items** (all IDs from C-001 through C-060, fully aligned with `issues/contracts.md`). + +--- + +## 2. Severity Counts + +| Severity | Count | +|----------|-------| +| 🔴 Critical | **6** (C-001 – C-006) | +| 🟠 High | **21** (C-007–C-012, C-021, C-027, C-028, C-034–C-042, C-050–C-052, C-055) | +| 🟡 Medium | **24** (C-013–C-018, C-020, C-024–C-026, C-032, C-033, C-036, C-043, C-044, C-046–C-048, C-054, C-056–C-060) | +| 🟢 Low | **9** (C-019, C-022, C-023, C-029–C-031, C-045, C-049, C-053) | +| **Total** | **60** | + +These six critical items are **ship-blockers**. They each enable direct loss of funds and must be remediated before the ACBU MVP can be deployed to Stellar mainnet. + +--- + +## 3. Critical Issues (🔴) — Ship Blockers + +### C-001 — Escrow `release` missing authorization +- **Area:** contracts/escrow +- **Evidence:** `acbu_escrow/src/lib.rs` (`release`) +- **Impact:** Any address can call `release(escrow_id)` and send funds held in escrow to the payee, enabling theft of any escrow created by an honest payer. +- **Fix direction:** Require payer (`payer.require_auth()`) or admin auth on `release` and `refund`; add explicit error for unauthorized caller. Maintain CEI ordering for token transfer. +- **Acceptance check:** Unauthorized `release` returns `ContractError::Unauthorized` at contract unit-test level; only payer or admin can settle an escrow. + +### C-002 — `mint_from_fiat` lacks off-chain settlement proof +- **Severity:** 🔴 Critical +- **Area:** contracts/minting +- **Evidence:** `acbu_minting/src/lib.rs` (`mint_from_fiat`) +- **Impact:** `mint_from_fiat` does not validate `fintech_tx_id` or that an off-chain fiat deposit has actually settled. Combined with `check_admin_or_user` semantics, recipients can mint ACBU without backing. +- **Fix direction:** Require admin-only minting for the fiat path (or verified settlement proof object), enforce uniqueness of `fintech_tx_id` in storage to prevent replay, and add an integration test that mints from a known-good provider. +- **Acceptance check:** Cannot mint from `mint_from_fiat` without a valid (admin, fintech_tx_id) tuple; replay of an existing `fintech_tx_id` returns the original transaction id and never mints twice. + +### C-003 — Escrow ID key collision +- **Severity:** 🔴 Critical +- **Area:** contracts/escrow +- **Evidence:** `acbu_escrow/src/lib.rs` storage keying +- **Impact:** Escrow keys are `(ESCROW, escrow_id)` only. Two payers using the same `escrow_id` cause the second `create` to overwrite the first, locking the first payer's funds in someone else's escrow. +- **Fix direction:** Include `payer` in the key tuple — `(ESCROW, payer, escrow_id)` — and reject duplicates with a domain error. +- **Acceptance check:** Property test confirms that two different payers calling `create` with the same `escrow_id` cannot collide and each can independently settle their escrow. + +### C-004 — `verify_reserves` uses wrong supply source +- **Severity:** 🔴 Critical +- **Area:** contracts/reserves +- **Evidence:** `acbu_reserve_tracker/src/lib.rs` (`verify_reserves`) +- **Impact:** `verify_reserves` reads `acbu_client.balance(&env.current_contract_address())` as the total minted supply. The reserve tracker does not hold ACBU, so this is always zero, and the function returns `true` early. Reserve checks trivially pass on every mint. +- **Fix direction:** Read the authoritative token supply via the token contract’s `total_supply` (or another trusted source stored at init), then compute `reserves_total_usd / minted_supply` against `min_ratio_bps` / `target_ratio_bps`. +- **Acceptance check:** Unit test asserts `verify_reserves(true_min)` returns `false` when the contract is undercollateralized and `true` when it is overcollateralized. + +### C-005 — Savings vault missing `require_auth` on deposit/withdraw +- **Severity:** 🔴 Critical +- **Area:** contracts/savings +- **Evidence:** `acbu_savings_vault/src/lib.rs` (deposit/withdraw) +- **Impact:** Anyone can call `withdraw(user=X, amount=Z)` and move X's funds, until the redeploy fixes auth. +- **Fix direction:** Add `user.require_auth()` to deposit and withdraw; emit explicit events; redeploy. +- **Acceptance check:** Withdraw requires the authenticated user’s address; non-owner calls fail with `ContractError::Unauthorized`. + +### C-006 — Lending pool missing `require_auth` on deposit/withdraw +- **Severity:** 🔴 Critical +- **Area:** contracts/lending +- **Evidence:** `acbu_lending_pool/src/lib.rs` (deposit/withdraw) +- **Impact:** Anyone can call `withdraw(lender=X, amount=Y)` and drain X's lender position. +- **Fix direction:** Add `lender.require_auth()` to deposit, withdraw, and any other lender-only methods; redeploy. +- **Acceptance check:** Withdraw requires the authenticated lender’s address; non-lender calls fail with `ContractError::Unauthorized`. + +--- + +## 4. High Severity Issues (🟠) + +### C-007 — Savings term not enforced +- **Area:** contracts/savings · **Evidence:** `acbu_savings_vault/src/lib.rs` +- **Impact:** `term_seconds` is stored but never checked on withdraw. Users can deposit and withdraw immediately, breaking the savings product semantics. +- **Fix direction:** Compare `env.ledger().timestamp()` to deposit timestamp + `term_seconds`. Allow early withdrawal only with an explicit penalty applied via `calculate_fee` policy. +- **Acceptance check:** Time-manipulation tests in the Soroban harness show that withdrawing before the term either fails or pays the documented penalty. + +### C-008 — `mint_from_fiat` missing max mint bound +- **Area:** contracts/minting · **Evidence:** `acbu_minting/src/lib.rs` (`mint_from_fiat`) +- **Impact:** `mint_from_usdc` enforces `MAX_MINT_AMOUNT`, but `mint_from_fiat` only enforces `MIN_MINT_AMOUNT`, allowing unbounded minting. +- **Fix direction:** Mirror the `MAX_MINT_AMOUNT` constant check from `mint_from_usdc`; expose the bound through storage for admin updates. +- **Acceptance check:** A mint request of `MAX_MINT_AMOUNT + 1` fails with `ContractError::InvalidAmount`. + +### C-009 — Burn basket integer division dust loss +- **Area:** contracts/burning · **Evidence:** `acbu_burning/src/lib.rs` (`burn_for_basket`) +- **Impact:** `amount_per_account = acbu_after_fee / recipient_accounts.len()` truncates. With many recipients, dust accumulates to user loss or an accounting mismatch off-chain. +- **Fix direction:** Allocate the remainder to the last recipient (or to the treasury in a `DustReleased` event) such that `sum(recipient_amounts) + fee == input` within 1 stroop. +- **Acceptance check:** Fuzz test against randomized recipient counts; total reconciles to `acbu_after_fee + fee` exactly. + +### C-010 — Escrow create lacks duplicate guard +- **Area:** contracts/escrow · **Evidence:** `acbu_escrow/src/lib.rs` (`create`) +- **Impact:** Even with C-003 fixed (per-payer key), the same payer calling `create` twice with the same `escrow_id` will overwrite their own escrow and lock prior funds. +- **Fix direction:** Reject with `ContractError::AlreadyExists` if the escrow already exists in storage; or use a monotonic per-payer sequence instead of caller-supplied ids. +- **Acceptance check:** A second `create` from the same payer with the same id returns an explicit error and does not modify storage. + +### C-011 — Minting loads oracle/reserve clients but does not call +- **Area:** contracts/minting · **Evidence:** `acbu_minting/src/lib.rs` +- **Impact:** `oracle` and `reserve_tracker` addresses are stored at init, but rates are hardcoded to 1:1 and reserve checks are skipped. Economic design is bypassed. +- **Fix direction:** Invoke the oracle to fetch the basket-weighted ACBU/USD rate; call `reserve_tracker.get_reserve_ratio()` before minting; reject if below `min_ratio_bps` or if oracle rate is stale beyond `UPDATE_INTERVAL_SECONDS`. +- **Acceptance check:** Mint fails when oracle is stale beyond threshold or when reserves are below the minimum. + +### C-012 — Burning loads oracle/reserve clients but does not call +- **Area:** contracts/burning · **Evidence:** `acbu_burning/src/lib.rs` +- **Impact:** Same as C-011 — oracle/reserve loaded but never invoked; burn FX rate is hardcoded. +- **Fix direction:** Use oracle medians + bounds checks before burn. Validate the redemption currency has sufficient reserves via `reserve_tracker.get_reserves()`. +- **Acceptance check:** Burn rejects out-of-range FX and insufficient reserves with explicit errors. + +### C-021 — Event payload schema drift vs backend listener +- **Area:** contracts/integration · **Evidence:** Mint/Burn events vs `acbu-backend` listener parsers +- **Impact:** Indexer silently drops events when field names, types, or decimals diverge between contract-emitted events and backend parser expectations. +- **Fix direction:** Generate a shared JSON schema or Rust types in a shared crate consumed by both contracts and the backend listener; cross-check fields in CI. +- **Acceptance check:** Golden vector tests across contracts and backend listeners pass against the same fixture. + +### C-027 — Loan events never emitted / loan logic missing +- **Area:** contracts/lending · **Evidence:** `acbu_lending_pool/src/lib.rs` +- **Impact:** `LoanCreatedEvent` and `RepaymentEvent` are defined but never emitted. Borrow/repay state transitions are not implemented on-chain. +- **Fix direction:** Implement `borrow(borrower, amount, interest_rate, duration_seconds)` and `repay(borrower, loan_id, amount)` with proper state machine; emit events at every transition. Coordinate with `acbu-lending-service` on backend consumption. +- **Acceptance check:** Loan lifecycle integration test (create → accrue → repay) emits every event in the right order with correct fields. + +### C-028 — Missing tests for core mint flows +- **Area:** contracts/qa · **Evidence:** `acbu_minting/tests/test.rs` coverage gaps +- **Impact:** Regressions in the most critical module are not caught; CI confidence in mint is low. +- **Fix direction:** Add unit + integration tests for `mint_from_usdc` and `mint_from_fiat` happy paths, error paths, and edge cases (zero, max, min, pause, oracle stale, reserves low). Enforce coverage threshold for `acbu_minting` in CI. +- **Acceptance check:** `cargo test -p acbu_minting` covers both flows; coverage gate set in CI. + +### C-034 — No contract versioning / upgrade story +- **Area:** contracts/ops · **Evidence:** Multiple crates +- **Impact:** No `version` field in storage, no documented migration playbook. Future upgrades cannot migrate user data safely. +- **Fix direction:** Add `version: u32` storage key at init; document upgrade + data migration playbook; pin invariant that user migration is opt-in and gated. +- **Acceptance check:** Upgrade runbook tested on testnet for at least one contract. + +### C-035 — Admin pause flags: verify on all state changes +- **Area:** contracts/governance · **Evidence:** Mint/burn/savings/lending +- **Impact:** Emergency pause may not cover all mutating entrypoints, leaving a window for continued mint/burn during an incident. +- **Fix direction:** Audit each `pub fn` for pause guard; add fuzz/property tests that paused contracts reject all mutating calls. +- **Acceptance check:** Fuzz test asserts no state change can occur while `paused=true`. + +### C-037 — Integer overflow review for all i128 money math +- **Area:** contracts/security · **Evidence:** All `*_amount` fields +- **Impact:** `i128` overflow can wrap in panic paths or produce incorrect comparisons downstream. +- **Fix direction:** Use checked math helpers in `shared`; explicit bounds on every multiplication; document per-field ranges. Add property tests covering extremes. +- **Acceptance check:** Property tests with extreme values never overflow silently. + +### C-038 — Authorization invocation tree for cross-contract calls +- **Area:** contracts/security · **Evidence:** Mint/burn calling token client +- **Impact:** Wrong invoker can break assumptions about who authorized a token transfer. +- **Fix direction:** Require auth on every external entrypoint; document the trust model in `INTEGRATION.md`; review token client call sites for `require_auth` propagation. +- **Acceptance check:** Threat model document updated and reviewed. + +### C-039 — Strict input validation for string IDs (`fintech_tx_id`) +- **Area:** contracts/minting · **Evidence:** `mint_from_fiat` parameters +- **Impact:** Garbage IDs pollute indexers, complicate partner reconciliation. +- **Fix direction:** Enforce length, charset, and uniqueness in storage; reject invalid ids at the contract boundary. +- **Acceptance check:** Invalid ids (oversize, non-printable, reused) are rejected with `ContractError::InvalidInput`. + +### C-040 — Decimal scaling consistency (7 decimals) across contracts +- **Area:** contracts/tokenomics · **Evidence:** Mint/burn/oracle +- **Impact:** Off-by-1e7 errors between contracts are catastrophic for users. +- **Fix direction:** Centralize `DECIMALS`, `stroop`, and unit-test helpers in `shared`; add cross-contract integration test for rounding. +- **Acceptance check:** Full mint→burn round trip reconciles within 1 stroop. + +### C-041 — Oracle staleness: max ledger age for rates +- **Area:** contracts/oracle · **Evidence:** `acbu_oracle/src/lib.rs` +- **Impact:** Old rates may be used in volatile markets, enabling arbitrage. +- **Fix direction:** Reject rates older than `STALENESS_THRESHOLD_LEDGERS` unless an admin override flag is present. +- **Acceptance check:** A stale rate cannot be used for new mints. + +### C-042 — Minimum oracle sources for quorum +- **Area:** contracts/oracle · **Evidence:** `acbu_oracle/src/lib.rs` +- **Impact:** A single-source feed can be exploited to push the median. +- **Fix direction:** Require `sources.len() >= K` for an update to be accepted; reject updates with `K-1` or fewer sources. +- **Acceptance check:** Cannot update with one manipulated feed. + +### C-050 — Integration tests: escrow full lifecycle +- **Area:** contracts/qa · **Evidence:** `acbu_escrow/tests` (add) +- **Impact:** Regressions go undetected on the escrow fixes for C-001/C-003/C-010. +- **Fix direction:** End-to-end tests for create → fund → release/dispute/refund covering both happy and adversarial paths. +- **Acceptance check:** Property tests cover at least 8 distinct flows. + +### C-051 — Integration tests: savings vault lock + interest +- **Area:** contracts/qa · **Evidence:** `acbu_savings_vault/tests` (expand) +- **Impact:** Lock and yield logic regressions silently corrupt user balances. +- **Fix direction:** Time manipulation tests in Soroban harness; cover under-term, exactly-at-term, and post-term cases. +- **Acceptance check:** Withdraw before term fails (or pays penalty); after-term withdraw succeeds with yield event matching spec. + +### C-052 — Integration tests: lending borrow/repay +- **Area:** contracts/qa · **Evidence:** `acbu_lending_pool/tests` (expand) +- **Impact:** Lending is high risk; needs coverage of liquidation if applicable. +- **Fix direction:** Cover borrow → accrue → repay → default scenarios; verify liquidation behavior per spec. +- **Acceptance check:** Loan default scenario matches documented behavior. + +### C-055 — Access control naming audit (`check_admin_or_user`) +- **Area:** contracts/authz · **Evidence:** Minting and other modules +- **Impact:** Misnamed helper may end up being too permissive; unintuitive caller set. +- **Fix direction:** Rename to a name that reflects actual semantics; add unit tests that cover all negative authorization cases. +- **Acceptance check:** Negative authorization tests catch every disallowed caller pattern in CI. + +## 5. Medium Severity Issues (🟡) + +### C-013 — Token WASM import uses zero SHA256 placeholder +- **Area:** contracts/build · **Evidence:** Mint/burn/reserve tracker token imports +- **Impact:** Integrity unverified; supply chain risk in production builds. +- **Fix direction:** Pin real wasm hash for `soroban_token_contract.wasm`; verify in CI against the deployed Stellar Asset Contract (SAC) artifact. +- **Acceptance check:** Build fails if the hash does not match the artifact. + +### C-014 — Double `.unwrap().unwrap()` pattern in escrow storage reads +- **Area:** contracts/escrow · **Evidence:** `acbu_escrow/src/lib.rs` +- **Impact:** Potential panics or undefined behavior if storage is malformed. +- **Fix direction:** Replace with a clean Option-handling helper that returns `ContractError::NotFound` on missing keys. +- **Acceptance check:** No `.unwrap().unwrap()` remains in production paths; missing storage returns a clean error. + +### C-015 — Double `.unwrap().unwrap()` pattern in savings vault +- **Area:** contracts/savings · **Evidence:** `acbu_savings_vault/src/lib.rs` +- **Impact:** Same as C-014. +- **Fix direction:** Replace with the same helper used in C-014. +- **Acceptance check:** No panic paths in normal operation; missing storage returns a structured error. + +### C-016 — Double `.unwrap().unwrap()` pattern in lending pool +- **Area:** contracts/lending · **Evidence:** `acbu_lending_pool/src/lib.rs` +- **Impact:** Same as C-014. +- **Fix direction:** Replace with the same helper used in C-014. +- **Acceptance check:** Consistent error handling across all three contracts. + +### C-017 — Oracle outlier detection is a no-op +- **Area:** contracts/oracle · **Evidence:** `acbu_oracle/src/lib.rs` +- **Impact:** Poisoned sources can move the median, undermining price integrity. +- **Fix direction:** Implement real outlier rejection or quarantine (e.g. `dropped_source` event) above `OUTLIER_THRESHOLD_BPS`. Emit an `OutlierDetected` event for downstream alerting. +- **Acceptance check:** Outlier source cannot move median beyond the configured bound; events emit on detection. + +### C-018 — Oracle unit test assertion incorrect vs median behavior +- **Area:** contracts/oracle · **Evidence:** `acbu_oracle/tests/test.rs` +- **Impact:** CI red or false confidence depending on changes. +- **Fix direction:** Fix the expected value to match `median(sources)`; add tests for multiple fixtures. +- **Acceptance check:** `cargo test -p acbu_oracle` passes reliably across all median cases. + +### C-020 — `median` allocates via `to_vec()` in shared util +- **Area:** contracts/shared · **Evidence:** `shared/src/lib.rs` (`median`) +- **Impact:** `no_std`/budget issues on Soroban. +- **Fix direction:** Replace with an in-place selection algorithm (`select_nth_unstable` style) within gas budget. +- **Acceptance check:** Contract budget measurements stay within limits on mainnet settings. + +### C-024 — Savings withdraw yield always zero +- **Area:** contracts/savings · **Evidence:** `acbu_savings_vault/src/lib.rs` (`WithdrawEvent`) +- **Impact:** Cannot build yield product UX honestly. +- **Fix direction:** Either implement a real accrual model or remove yield claims from the product spec. +- **Acceptance check:** Event `yield_amount` matches computed yield in tests; if accrual is removed, the field is deleted and the docs are updated. + +### C-025 — Lending fee rate unused +- **Area:** contracts/lending · **Evidence:** `acbu_lending_pool/src/lib.rs` +- **Impact:** Economic model incomplete. +- **Fix direction:** Apply fees on interest/repayments as designed; emit fee events. +- **Acceptance check:** Fee events are non-zero in the happy path; off-chain reconciliation agrees. + +### C-026 — Savings fee rate unused +- **Area:** contracts/savings · **Evidence:** `acbu_savings_vault/src/lib.rs` +- **Impact:** Same as C-025 for savings deposits. +- **Fix direction:** Apply deposit/withdraw fee policy consistently. +- **Acceptance check:** Fee events reflected in balances and off-chain reporting. + +### C-032 — Predictable `transaction_id` in minting +- **Area:** contracts/minting · **Evidence:** `acbu_minting/src/lib.rs` +- **Impact:** Correlation attacks and partner id collisions become trivial. +- **Fix direction:** Compute `transaction_id = sha256(user || amount || external_ref || ledger_seq)` (or similar), and ensure uniqueness via storage or sequence counter. +- **Acceptance check:** Generated IDs are globally unique with high probability; fuzz test confirms no collision over a million samples. + +### C-033 — Reserve tracker emits no events on updates +- **Area:** contracts/reserves · **Evidence:** `acbu_reserve_tracker/src/lib.rs` +- **Impact:** Harder to index reserve history for transparency dashboards. +- **Fix direction:** Emit `ReserveUpdateEvent` on every `update_reserve` call. +- **Acceptance check:** Listener can reconstruct complete reserve timeline from emitted events. + +### C-036 — Reentrancy class issues via token callbacks +- **Area:** contracts/security · **Evidence:** Token transfers inside contracts +- **Impact:** Soroban reentrancy differs from EVM but token contract behavior still needs audit. +- **Fix direction:** Verify CEI ordering; document any reliance on token contract non-reentrancy; check Soroban SDK guarantees. +- **Acceptance check:** External reviewer audit notes checked in. + +### C-043 — Emergency multisig for admin operations +- **Area:** contracts/governance · **Evidence:** Admin-only methods +- **Impact:** Single key compromise is catastrophic. +- **Fix direction:** Use Soroban auth pattern with M-of-N multisig threshold; harden against single-point compromise. +- **Acceptance check:** Admin action requires configured M-of-N in tests. + +### C-044 — Contract size/compute budget regression tests +- **Area:** contracts/qa · **Evidence:** CI pipeline +- **Impact:** Near-limit contracts fail after small edits. +- **Fix direction:** Track contract size and compute budget metrics in CI; alert on regression beyond threshold. +- **Acceptance check:** CI fails the PR if budget exceeds threshold. + +### C-046 — `cargo audit` / supply chain monitoring +- **Area:** contracts/security · **Evidence:** Rust dependencies +- **Impact:** Transitive CVEs in Soroban ecosystem. +- **Fix direction:** Add audit step in CI; pin critical dependencies. +- **Acceptance check:** CI fails on critical advisories (or documented waiver). + +### C-047 — Formalize invariants documentation per contract +- **Area:** contracts/docs · **Evidence:** `INTEGRATION.md` / `SMART_CONTRACT_SPEC` +- **Impact:** Auditors slow; engineers drift. +- **Fix direction:** Add `INVARIANTS.md` per crate linking each public fn to its pre/post conditions; review in PRs. +- **Acceptance check:** Each public fn lists pre/post conditions in code comments or invariants doc. + +### C-048 — Testnet vs mainnet feature flags in code +- **Area:** contracts/ops · **Evidence:** `dummy_token` etc. +- **Impact:** Accidental mainnet deploy of test code paths. +- **Fix direction:** Compile-time features or explicit network checks at init; mainnet builds must not reference test-only tokens. +- **Acceptance check:** Mainnet build cannot reference dummy token. + +### C-054 — Consistent error codes for clients +- **Area:** contracts/api-ux · **Evidence:** All contracts +- **Impact:** Clients cannot map errors to UX flows. +- **Fix direction:** Standard `ContractError` with stable discriminants across the workspace; document in OpenAPI/Soroban spec. +- **Acceptance check:** Spec lists error codes and clients can map them to user-facing messages. + +### C-056 — Token allowance assumptions if using allowance +- **Area:** contracts/token · **Evidence:** Mint/burn pulling user tokens +- **Impact:** Wrong allowance patterns block users or allow drains. +- **Fix direction:** Document pull vs push model; align with frontend allowance UX; add matrix in `INTEGRATION.md`. +- **Acceptance check:** Manual test matrix for allowances passes for at least the three flows mint, burn, savings deposit. + +### C-057 — Burn path: validate recipient accounts non-empty + distinct +- **Area:** contracts/burning · **Evidence:** `burn_for_basket` recipients +- **Impact:** Duplicate recipients could double-pay off-chain mapping. +- **Fix direction:** Enforce non-empty and deduplicate (or reject duplicates). +- **Acceptance check:** Duplicates rejected deterministically and emit a clear error. + +### C-058 — Mint path: validate recipient is a real account +- **Area:** contracts/minting · **Evidence:** Recipient address parameter +- **Impact:** Minting to contract-only addresses strands ACBU. +- **Fix direction:** Optional claim flow (mint to claim PDA redeemed by user) or accounts allowlist pattern. +- **Acceptance check:** Stranded mint rate is negligible / documented. + +### C-059 — Reserve tracker initialization parameters validation +- **Area:** contracts/reserves · **Evidence:** `acbu_reserve_tracker` init +- **Impact:** Bad init can brick the policy. +- **Fix direction:** Validate ranges (`min_ratio < target_ratio < BASIS_POINTS`); freeze critical params after launch. +- **Acceptance check:** Init cannot set impossible targets. + +### C-060 — Oracle admin rotation workflow +- **Area:** contracts/ops · **Evidence:** `acbu_oracle` admin +- **Impact:** Lost admin key bricks updates. +- **Fix direction:** Two-step transfer + timelock. +- **Acceptance check:** Rotation runbook tested on testnet. + +--- + +## 6. Low Severity Issues (🟢) + +### C-019 — Redundant DECIMALS multiply/divide in burn path +- **Area:** contracts/burning · **Evidence:** `acbu_burning/src/lib.rs` +- **Impact:** Noise / audit confusion. +- **Fix direction:** Simplify; keep explicit where needed for readability. +- **Acceptance check:** Diff is purely refactor with identical behavior under fuzz. + +### C-022 — Magic number vs `BASIS_POINTS` constant inconsistency +- **Area:** contracts/fees · **Evidence:** `acbu_savings_vault`, `acbu_lending_pool` +- **Impact:** Fee math harder to audit consistently. +- **Fix direction:** Import `shared::BASIS_POINTS` everywhere. +- **Acceptance check:** Grep shows single `BASIS_POINTS` definition. + +### C-023 — Per-account BurnEvent fee reporting mismatch +- **Area:** contracts/burning · **Evidence:** `acbu_burning/src/lib.rs` events +- **Impact:** Off-chain accounting reconciliation breaks. +- **Fix direction:** Emit totals + per-recipient net amounts consistently so the indexer can reconcile to the original input. +- **Acceptance check:** Indexer balances to events within 1 stroop. + +### C-029 — Unused import noise in minting crate +- **Area:** contracts/hygiene · **Evidence:** `acbu_minting/src/lib.rs` +- **Impact:** Clutter. +- **Fix direction:** Remove unused imports; add `cargo clippy --deny warnings` in CI. +- **Acceptance check:** `cargo clippy` clean. + +### C-030 — Empty recipient list style / checks +- **Area:** contracts/burning · **Evidence:** `acbu_burning/src/lib.rs` +- **Impact:** Minor readability. +- **Fix direction:** Use `is_empty()`; add explicit error. +- **Acceptance check:** Clear error when recipients empty. + +### C-031 — Oracle RateUpdateEvent validators empty +- **Area:** contracts/oracle · **Evidence:** `acbu_oracle/src/lib.rs` +- **Impact:** Downstream cannot audit which validators contributed. +- **Fix direction:** Populate validator set in event from the active signers for that update. +- **Acceptance check:** Event includes non-empty validator metadata. + +### C-045 — Deterministic builds: `Cargo.lock` policy +- **Area:** contracts/devx · **Evidence:** `acbu-smart-contract/Cargo.lock` +- **Impact:** Non-reproducible deployments. +- **Fix direction:** CI verifies `cargo build --locked`. +- **Acceptance check:** Locked builds pass in CI. + +### C-049 — Wasm artifact `soroban_token_contract.wasm` in repo +- **Area:** contracts/build · **Evidence:** Root `soroban_token_contract.wasm` +- **Impact:** Binary blobs in git complicate review. +- **Fix direction:** Store as release artifacts; pin hash in source. +- **Acceptance check:** Repo size reduced (or documented policy inline). + +### C-053 — Gas griefing: unbounded vectors in events +- **Area:** contracts/perf · **Evidence:** Events with large vectors +- **Impact:** Large transactions fail or become expensive. +- **Fix direction:** Cap `recipients.len()` per call; paginate off-chain with a follow-up event for continuation flows. +- **Acceptance check:** Maximum recipients enforced with clear error. + +--- + +## 7. Legacy 34-Item Origin List + +The following list was previously the only contents of this file. Items are kept here as a stable cross-reference; their detailed entries are in the sections above (or in `issues/contracts.md` if explicitly listed there). Items marked **(moved)** have been superseded by the equivalent entry in the detailed catalog; items marked **(archived)** describe issues already considered and not requiring separate tracking. + +### Critical +1. **Missing access control on escrow `release`** – C-001 *(moved)* +2. **Unrestricted minting in `mint_from_fiat`** – C-002 *(moved)* +3. **Escrow ID collision** – C-003 *(moved)* +4. **Incorrect total supply in `verify_reserves`** – C-004 *(moved)* +5. **Missing auth checks in savings vault** – C-005 *(moved)* +6. **Missing auth checks in lending pool** – C-006 *(moved)* + +### High +7. **Term not enforced in savings vault** – C-007 *(moved)* +8. **No max amount check in `mint_from_fiat`** – C-008 *(moved)* +9. **Integer division truncation in `burn_for_basket`** – C-009 *(moved)* +10. **No duplicate escrow check** – C-010 *(moved)* +11. **Oracle and reserve tracker unused in minting** – C-011 *(moved)* +12. **Oracle and reserve tracker unused in burning** – C-012 *(moved)* + +### Medium +13. **Token WASM import uses zero SHA256** – C-013 *(moved)* +14. **Double `.unwrap().unwrap()` in escrow** – C-014 *(moved)* +15. **Double `.unwrap().unwrap()` in savings vault** – C-015 *(moved)* +16. **Double `.unwrap().unwrap()` in lending pool** – C-016 *(moved)* +17. **Outlier detection has no effect in oracle** – C-017 *(moved)* +18. **Incorrect oracle test assertion** – C-018 *(moved)* +19. **Redundant calculation in burning** – C-019 *(moved)* +20. **`median` uses `to_vec()` in no_std** – C-020 *(moved)* +21. **Contract events vs backend listeners** – C-021 *(moved)* + +### Low +22. **Magic number for fee cap in savings and lending** – C-022 *(moved)* +23. **Incorrect fee in per-account BurnEvent** – C-023 *(moved)* +24. **`yield_amount` always 0 in savings** – C-024 *(moved)* +25. **Fee rate stored but unused in lending pool** – C-025 *(moved)* +26. **Fee rate stored but unused in savings vault** – C-026 *(moved)* +27. **Loan events never emitted** – C-027 *(moved)* +28. **No tests for core minting flows** – C-028 *(moved)* + +### Trivial +29. **Unused import** in `acbu_minting/src/lib.rs` – C-029 *(moved)* +30. **`len() == 0` style** in `acbu_burning/src/lib.rs` – C-030 *(moved)* +31. **Empty validators in event** in `acbu_oracle/src/lib.rs` – C-031 *(moved)* +32. **Weak `transaction_id` generation** in `acbu_minting/src/lib.rs` – C-032 *(moved)* +33. **No events in reserve tracker** in `acbu_reserve_tracker/src/lib.rs` – C-033 *(moved)* +34. **No upgrade or versioning** across multiple contracts – C-034 *(moved)* + +--- + +## 8. Resolution Tracker (Fix Status) + +> **Format:** `ID · title · status · linked PR / commit · owner` +> +> **Forward-looking template.** This is a placeholder grid designed for the day a fix lands. Every item is currently 🟡 Open; reviewers should not read uniformity of status as stagnation. When a fix merges, the row flips to ✅ Fixed and a PR/commit link is added. Example anchors below show what a real fixed row looks like. + +| ID | Title | Status | Notes | +|----|-------|--------|-------| +| _(example)_ | _(example anchor: prior PR #14 closed issue #1)_ | ✅ Fixed (PR #14 merged) | Historical anchor — not a contracts item | +| C-001 | Escrow `release` missing authorization | 🟡 Open (tracked separately) | Blocked on auth refactor for C-005/C-006 | +| C-002 | `mint_from_fiat` lacks off-chain settlement proof | 🟡 Open | Admin-only path + uniqueness required | +| C-003 | Escrow ID key collision | 🟡 Open | Payer+id tuple planned | +| C-004 | `verify_reserves` uses wrong supply source | 🟡 Open | Read `total_supply` from token contract | +| C-005 | Savings vault missing `require_auth` | 🟡 Open | Redeploy gating MVP | +| C-006 | Lending pool missing `require_auth` | 🟡 Open | Redeploy gating MVP | +| C-007 | Term not enforced | 🟡 Open | Coupled to C-005 | +| C-008 | `mint_from_fiat` missing max bound | 🟡 Open | Coupled to C-002 | +| C-009 | Burn basket dust loss | 🟡 Open | Allocate remainder to last | +| C-010 | Escrow create duplicate guard | 🟡 Open | Coupled to C-003 | +| C-011 | Minting oracle/reserve unused | 🟡 Open | Rate fetching required | +| C-012 | Burning oracle/reserve unused | 🟡 Open | Rate fetching required | +| C-013 | WASM zero SHA256 | 🟡 Open | Pin hash in CI | +| C-014..C-016 | Double unwrap patterns | 🟡 Open | Standardize helper | +| C-017 | Oracle outlier detection no-op | 🟡 Open | Implement quarantine | +| C-018 | Oracle test assertion | 🟡 Open | Fix expected value | +| C-019 | Redundant DECIMALS | 🟢 Trivial | Refactor PR | +| C-020 | `median` to_vec in no_std | 🟡 Open | In-place algorithm | +| C-021 | Event schema drift | 🟡 Open | Shared types crate | +| C-022 | Magic number fees | 🟢 Trivial | Use shared constant | +| C-023 | Per-account BurnEvent fee | 🟡 Open | Reconcile events | +| C-024 | Yield always 0 | 🟡 Open | Accrual model | +| C-025 | Lending fee rate unused | 🟡 Open | Apply policy | +| C-026 | Savings fee rate unused | 🟡 Open | Apply policy | +| C-027 | Loan events missing | 🟡 Open | Implement borrow/repay | +| C-028 | No core mint tests | 🟡 Open | Coverage gate CI | +| C-029 | Unused import | 🟢 Trivial | Lint PR | +| C-030 | Len()==0 style | 🟢 Trivial | Refactor PR | +| C-031 | Empty validators in event | 🟢 Trivial | Fill in event | +| C-032 | Predictable transaction_id | 🟡 Open | Hash-based id | +| C-033 | Reserve tracker no events | 🟡 Open | Emit on update | +| C-034 | No versioning/upgrade | 🟡 Open | Runbook + storage | +| C-035 | Pause not all-encompassing | 🟡 Open | Audit + fuzz | +| C-036 | Reentrancy via token | 🟡 Open | External review | +| C-037 | i128 overflow | 🟡 Open | Checked math | +| C-038 | Auth invocation tree | 🟡 Open | Threat model doc | +| C-039 | fintech_tx_id validation | 🟡 Open | Reject garbage | +| C-040 | 7-decimals consistency | 🟡 Open | Centralize constant | +| C-041 | Oracle staleness threshold | 🟡 Open | Reject stale | +| C-042 | Min oracle sources | 🟡 Open | Quorum required | +| C-043 | Emergency multisig | 🟡 Open | M-of-N pattern | +| C-044 | Budget regression tests | 🟡 Open | CI metric | +| C-045 | Deterministic builds | 🟢 Trivial | `cargo build --locked` | +| C-046 | cargo audit | 🟡 Open | CI step | +| C-047 | INVARIANTS per contract | 🟡 Open | Doc per crate | +| C-048 | Testnet/mainnet flags | 🟡 Open | Compile-time | +| C-049 | WASM blob in repo | 🟢 Trivial | Release artifact | +| C-050..C-052 | End-to-end integration tests | 🟡 Open | Property tests | +| C-053 | Gas griefing | 🟢 Trivial | Cap + paginate | +| C-054 | Consistent error codes | 🟡 Open | Standardize enum | +| C-055 | Auth helper naming | 🟡 Open | Rename + tests | +| C-056 | Token allowance assumptions | 🟡 Open | Document matrix | +| C-057 | Recipient uniqueness | 🟡 Open | Reject duplicates | +| C-058 | Mint to real account | 🟡 Open | Claim flow | +| C-059 | Reserve init validation | 🟡 Open | Range checks | +| C-060 | Oracle admin rotation | 🟡 Open | Two-step + timelock | + +> **Status legend** — 🟢 Trivial/cosmetic · 🟡 Open (tracked) · 🔵 In review · ✅ Fixed (PR linked) +> +> **Reminder when updating:** when an external PR closes an issue, replace `🟡 Open` with `✅ Fixed` and append the merged PR link in the Notes column. Do not rewrite history; the row itself is the audit trail. --- -## Critical +## 9. Cross-Reference Map -1. **Missing access control on escrow `release`** – acbu_escrow/src/lib.rs: `release` has no auth check. Any address can call `release(escrow_id)` and send funds to the payee. -2. **Unrestricted minting in `mint_from_fiat`** – acbu_minting/src/lib.rs: `mint_from_fiat` does not validate `fintech_tx_id` or off-chain fiat deposits. With `check_admin_or_user`, the recipient can call it for themselves and mint ACBU without real fiat backing. -3. **Escrow ID collision** – acbu_escrow/src/lib.rs: Escrow keys use only `(ESCROW, escrow_id)`. Two payers can use the same `escrow_id`; the second create overwrites the first. The first payer's funds become unrecoverable. -4. **Incorrect total supply in `verify_reserves`** – acbu_reserve_tracker/src/lib.rs: `verify_reserves` uses `acbu_client.balance(&env.current_contract_address())` as total supply. The reserve tracker does not hold ACBU, so this is always 0. The function returns `true` early and reserve checks never actually run. -5. **Missing auth checks in savings vault** – acbu_savings_vault/src/lib.rs: `deposit` and `withdraw` lack `user.require_auth()`. Anyone can call `withdraw(user=X, term_seconds=Y, amount=Z)` and move funds without X's authorization. -6. **Missing auth checks in lending pool** – acbu_lending_pool/src/lib.rs: `deposit` and `withdraw` lack `lender.require_auth()`. Anyone can call `withdraw(lender=X, amount=Y)` and drain X's balance. +| Document | Relationship to this file | +|----------|---------------------------| +| [`../../issues/contracts.md`](../../issues/contracts.md) | **Live triage-ready catalog.** Same IDs and severities; entries are condensed for daily use. | +| [`../../issues/MASTER_INDEX.md`](../../issues/MASTER_INDEX.md) | Master index across backend/frontend/contracts backlogs. | +| [`../../issues/backend.md`](../../issues/backend.md) | Backend MVP issues (B-001..B-075). | +| [`../../issues/frontend.md`](../../issues/frontend.md) | Frontend MVP issues (F-001..F-065). | +| [`../SMART_CONTRACT_SPEC.MD`](../SMART_CONTRACT_SPEC.MD) | Detailed on-chain spec (interfaces, types, events, invariants, security model). | +| [`../../DOCS/SMART_CONTRACT_SPEC.MD`](../../DOCS/SMART_CONTRACT_SPEC.MD) | Spec doc used in MVPs; duplicates the contract-side spec. | +| [`../../DOCS/ARCHITECTURE_DIAGRAMS.MD`](../../DOCS/ARCHITECTURE_DIAGRAMS.MD) | Mint/burn/reserve/oracle diagrams. | +| [`../API_AND_CONTRACTS_REFERENCE.MD`](../API_AND_CONTRACTS_REFERENCE.MD) | Routes ↔ contracts mapping. | +| [`../../TECHNICAL/ARCHITECTURE.MD`](../../TECHNICAL/ARCHITECTURE.MD) | High-level architecture. | +| [`../../TECHNICAL/ORACLE_SYSTEM.MD`](../../TECHNICAL/ORACLE_SYSTEM.MD) | Oracle multi-source design context for C-011/012/017/018/041/042. | +| [`../../TECHNICAL/RESERVE_MANAGEMENT.MD`](../../TECHNICAL/RESERVE_MANAGEMENT.MD) | Reserve model context for C-004/C-059. | +| [`../../TECHNICAL/PRICING_MECHANISM.MD`](../../TECHNICAL/PRICING_MECHANISM.MD) | Pricing/basket-weight context for C-040/C-024/C-025/C-026. | +| [`../PROJECT_STRUCTURE.MD`](../PROJECT_STRUCTURE.MD) | Repo layout (where the contract source lives). | +| [`../TASK_BREAKDOWN.MD`](../TASK_BREAKDOWN.MD) | Stage-by-stage tasks (where fixes are scheduled). | +| [`../../DOCS/IMPLEMENTATION_PLAN.MD`](../../DOCS/IMPLEMENTATION_PLAN.MD) | Phase-by-phase remediation timeline. | +| [`../../correction.md`](../../correction.md) | Standing-list of additional items curated for fast triage. | -## High +--- -7. **Term not enforced in savings vault** – acbu_savings_vault/src/lib.rs: `term_seconds` is stored but never checked on withdrawal. Users can deposit and withdraw immediately; there is no lock period. -8. **No max amount check in `mint_from_fiat`** – acbu_minting/src/lib.rs: `mint_from_usdc` enforces `max_mint_amount`, but `mint_from_fiat` only checks `min_amount`, allowing unbounded minting. -9. **Integer division truncation in `burn_for_basket`** – acbu_burning/src/lib.rs: `amount_per_account = acbu_after_fee / (recipient_accounts.len() as i128)` truncates. With many recipients, dust is lost and never accounted for. -10. **No duplicate escrow check** – acbu_escrow/src/lib.rs: `create` does not check if `escrow_id` already exists. Overwriting an existing escrow can lock prior funds. -11. **Oracle and reserve tracker unused in minting** – acbu_minting/src/lib.rs: `oracle` and `reserve_tracker` are loaded but never called. Rates are hardcoded to 1:1 and reserve checks are skipped. -12. **Oracle and reserve tracker unused in burning** – acbu_burning/src/lib.rs: Same as minting — oracle and reserve tracker are loaded but not used; rates are hardcoded. +## 10. Top Remediations (ship-safety order) -## Medium +Order these fixes in the MVP launch runbook before deploying mainnet: -13. **Token WASM import uses zero SHA256** – In acbu_minting, acbu_burning, and acbu_reserve_tracker, `soroban_token_contract.wasm` is imported with `sha256 = "0x0000...0"`. This is a placeholder; production builds should use the real WASM hash for integrity and security. -14. **Double `.unwrap().unwrap()` in escrow** – acbu_escrow/src/lib.rs: Multiple storage reads use `.get(...).unwrap().unwrap()`. Storage `get` returns `Option`, so a single `.unwrap()` is expected. The second `.unwrap()` may panic or indicate a type mismatch. -15. **Double `.unwrap().unwrap()` in savings vault** – acbu_savings_vault/src/lib.rs: Same problematic double-unwrap pattern. -16. **Double `.unwrap().unwrap()` in lending pool** – acbu_lending_pool/src/lib.rs: Same pattern. -17. **Outlier detection has no effect in oracle** – acbu_oracle/src/lib.rs: Outliers are detected but only marked with a comment "Log outlier but continue with median". No logging, rejection, or alert occurs. -18. **Incorrect oracle test assertion** – acbu_oracle/tests/test.rs: Test expects `stored_rate == rate` (1234567), but the contract stores `median(sources)` (1235000). The test will fail. -19. **Redundant calculation in burning** – acbu_burning/src/lib.rs: `(acbu_after_fee * DECIMALS) / DECIMALS` is equivalent to `acbu_after_fee`; the multiplication and division cancel out. -20. **`median` uses `to_vec()` in no_std** – shared/src/lib.rs: `median` allocates with `values.to_vec()`. In `no_std` Soroban contracts this may not be available or may require `alloc`. -21. **Contract events vs backend listeners** – Verify that MintEvent and BurnEvent payloads (field names, types, decimals) match what the backend event listeners expect, to avoid parsing or indexing failures. +1. **C-001 / C-005 / C-006** — Auth on escrow/savings/lending (single PR or coordinated). +2. **C-002** — Mint only with verified settlement proof. +3. **C-003 / C-010** — Per-payer escrow keys + duplicate guard. +4. **C-004** — Real token-supply source in reserve tracker. +5. **C-011 / C-012** — Wire oracle + reserve checks into mint/burn. +6. **C-007 / C-024** — Term + yield honoring in savings. +7. **C-008** — Mirror mint bound on `mint_from_fiat`. +8. **C-009 / C-023** — Reconcile burn accounting + events. +9. **C-013** — Pin token WASM hash. +10. **C-014 / C-015 / C-016** — Replace double-unwrap helpers. +11. **C-017 / C-021** — Outlier enforcement + shared event schemas. +12. **C-027 / C-050 / C-051 / C-052** — Lifecycle + integration tests. -## Low +--- -22. **Magic number for fee cap in savings and lending** – acbu_savings_vault and acbu_lending_pool use `10_000` instead of `shared::BASIS_POINTS`, unlike minting and burning. -23. **Incorrect fee in per-account BurnEvent** – acbu_burning/src/lib.rs: Each `BurnEvent` uses `calculate_fee(amount_per_account, fee_rate)`, but the fee is taken from the total `acbu_amount`. Per-account fees in events don't match actual fee accounting. -24. **`yield_amount` always 0 in savings** – acbu_savings_vault/src/lib.rs: `WithdrawEvent` always sets `yield_amount: 0`, suggesting yield logic is not implemented. -25. **Fee rate stored but unused in lending pool** – acbu_lending_pool/src/lib.rs: `fee_rate` is stored during initialization but never applied to any operation. -26. **Fee rate stored but unused in savings vault** – acbu_savings_vault/src/lib.rs: Same — `fee_rate` is stored but not applied. -27. **Loan events never emitted** – acbu_lending_pool/src/lib.rs: `LoanCreatedEvent` and `RepaymentEvent` are defined but never emitted; lending/repayment logic appears missing. -28. **No tests for core minting flows** – acbu_minting/tests/test.rs: Tests cover init, pause, and fee rate, but not `mint_from_usdc` or `mint_from_fiat`. +## 11. Maintenance -## Trivial +- **New issues** — Add to `issues/contracts.md` first (canonical triage). Mirror to this file's Section 4–6 with the next stable ID. +- **Closed fixes** — Promote the fix to `✅ Fixed (PR linked)` in Section 8 and link to the merged PR. +- **Audit-changing decisions** — Update Section 3 first (Critical) so reviewers see the most consequential revisions. +- **Cross-doc references** — Update `issues/MASTER_INDEX.md` summary counts when severities change. + +--- + +## Related Documents + +- [Live contracts issue catalog](../../issues/contracts.md) +- [Master backlog index](../../issues/MASTER_INDEX.md) +- [Backend issues](../../issues/backend.md) +- [Frontend issues](../../issues/frontend.md) +- [Smart contract spec (root copy)](../SMART_CONTRACT_SPEC.md) +- [Smart contract spec (DOCS copy)](../../DOCS/SMART_CONTRACT_SPEC.MD) +- [Project structure map](../PROJECT_STRUCTURE.md) +- [Architecture (TECHNICAL)](../../TECHNICAL/ARCHITECTURE.MD) +- [Oracle system design](../../TECHNICAL/ORACLE_SYSTEM.MD) + +--- -29. **Unused import** – acbu_minting/src/lib.rs: `Vec` is imported but not used. -30. **`len() == 0` style** – acbu_burning/src/lib.rs: `recipient_accounts.len() == 0` could be `recipient_accounts.is_empty()`. -31. **Empty validators in event** – acbu_oracle/src/lib.rs: `RateUpdateEvent` uses `validators: Vec::new(&env)` instead of the actual validator set. -32. **Weak `transaction_id` generation** – acbu_minting/src/lib.rs: `transaction_id` is `format!("mint_{}", ledger.sequence())`, which is predictable and not globally unique. -33. **No events in reserve tracker** – acbu_reserve_tracker/src/lib.rs: Reserve updates do not emit events, making off-chain tracking harder. -34. **No upgrade or versioning** – Multiple contracts: No version field or upgrade path; contracts cannot be migrated safely. +_Last consolidated: June 2026. Source content merged from legacy `PROJECT/issues/CONTRACTS_ISSUES.md` list (34 items) and canonical [`issues/contracts.md`](../../issues/contracts.md) (60 items). Severity buckets, IDs, and totals fully aligned with canonical catalog; legacy list is preserved in Section 7 for reference but every item now resolves to a canonical C-### ID._ From 6583ac6e94e00111c3f2034585abde64b06992fd Mon Sep 17 00:00:00 2001 From: Adiz4415 Date: Sat, 20 Jun 2026 12:33:10 +0000 Subject: [PATCH 02/11] docs(backend): consolidate BACKEND_ISSUES.md catalog --- PROJECT/issues/BACKEND_ISSUES.md | 827 ++++++++++++++++++++++++++++--- 1 file changed, 755 insertions(+), 72 deletions(-) diff --git a/PROJECT/issues/BACKEND_ISSUES.md b/PROJECT/issues/BACKEND_ISSUES.md index 1435195..8f1a61b 100644 --- a/PROJECT/issues/BACKEND_ISSUES.md +++ b/PROJECT/issues/BACKEND_ISSUES.md @@ -1,76 +1,759 @@ -# Backend – Known Issues +# Backend — Known Issues -Issues found in the Node/Express API, services, and jobs. Add new items below as numbered list entries. +This document is the **single, durable long-form reference** for known issues in the ACBU backend (`acbu-backend`, Node.js/Express + Prisma/PostgreSQL + MongoDB + RabbitMQ + Stellar SDK), covering all routes, services, jobs, middleware, utils, config, security, observability, compliance, and ops. + +> **How to use** +> +> - Each issue is structured as: **severity · area · evidence · impact · fix direction · acceptance check**. +> - Items are ordered by severity (Critical → Low), then by ID for stable cross-referencing. +> - Provenance: this file consolidates the legacy 56-item annotated list previously at `PROJECT/issues/BACKEND_ISSUES.md` with the canonical 75-item triage-ready list at `issues/backend.md`. The canonical list at `issues/backend.md` remains the **live working backlog**; this file is the durable version-of-record. +> - Legacy items whose content maps to a canonical `B-###` ID are tagged **(moved)**; legacy items that go beyond the canonical list (newer findings) are tagged **(new)** and retained verbatim because they pre-date the canonical rewrite. +> - When an item is fixed, the corresponding entry is removed from the working lists (`issues/backend.md`) and the resolution row flips to ✅ Fixed in Section 8 with a merged-PR link. +> - **Severity legend:** 🔴 Critical · 🟠 High · 🟡 Medium · 🟢 Low + +--- + +## 1. Summary Table + +| ID | Severity | Area | Title (canonical) | +|----|----------|------|---------| +| B-001 | 🟠 High | backend/minting | Mint basket deposit limits use wrong USD proxy | +| B-002 | 🟠 High | backend/money | Floating `Number()` on money paths | +| B-003 | 🟠 High | backend/jobs | USDC convert job infinite requeue on failure | +| B-004 | 🟠 High | backend/webhooks | Webhook delivery retry semantics | +| B-005 | 🔴 Critical | backend/webhooks | Webhook signature verification fail-open risk | +| B-006 | 🔴 Critical | backend/auth | Recovery unlock as single-factor account recovery | +| B-007 | 🟠 High | backend/minting | Client-supplied mint recipient vs user wallet | +| B-008 | 🟠 High | backend/transfers | Transfer service Decimal typing | +| B-009 | 🟠 High | backend/fees | Burn fee policy threshold logic | +| B-010 | 🟠 High | backend/reserves | ReserveTracker total supply from DB not chain | +| B-011 | 🟠 High | backend/limits | Org-scoped transaction limits with null userId | +| B-012 | 🟡 Medium | backend/savings | Savings controller input validation | +| B-013 | 🟠 High | backend/auth | Placeholder / invalid Stellar address on signup | +| B-014 | 🟡 Medium | backend/wallet | Wallet activation funding asset choice | +| B-015 | 🟡 Medium | backend/stellar | Hardcoded Soroban inclusion fees | +| B-016 | 🟠 High | backend/stellar | Stellar event listener scope and error handling | +| B-017 | 🟠 High | backend/kyc | KYC machine layer is placeholder | +| B-018 | 🟡 Medium | backend/government | Government treasury aggregation stub | +| B-019 | 🟡 Medium | backend/salary | Salary APIs not implemented | +| B-020 | 🟡 Medium | backend/enterprise | Enterprise bulk transfer not implemented | +| B-021 | 🟡 Medium | backend/enterprise | Enterprise treasury view stub | +| B-022 | 🟡 Medium | backend/bills | Bills catalog and pay not implemented | +| B-023 | 🟡 Medium | backend/investment | Investment deployable allocation ignores deployed | +| B-024 | 🟡 Medium | backend/jobs | Investment withdrawal notifications for org requests | +| B-025 | 🟡 Medium | backend/investment | Yield accounting stub | +| B-026 | 🟠 High | backend/audit | Audit write failures only logged | +| B-027 | 🟡 Medium | backend/cache | Cache `deletePattern` ReDoS risk | +| B-028 | 🟠 High | backend/ratelimit | API key rate limiter non-atomic increment | +| B-029 | 🟡 Medium | backend/ratelimit | Rate limiter Mongo outage fail-open | +| B-030 | 🟢 Low | backend/ratelimit | Standard IP rate limit message mismatch | +| B-031 | 🟡 Medium | backend/ops | Deep health and metrics routes are public | +| B-032 | 🟢 Low | backend/ops | Shallow `/health` does not prove readiness | +| B-033 | 🟡 Medium | backend/docs | Swagger UI publicly mounted | +| B-034 | 🟡 Medium | backend/docs | OpenAPI drift vs implementation | +| B-035 | 🟢 Low | backend/devx | README still references npm only | +| B-036 | 🟡 Medium | backend/devx | `postinstall` runs prisma generate + tsc | +| B-037 | 🟡 Medium | backend/qa | Jest `passWithNoTests` weak gate | +| B-038 | 🟡 Medium | backend/api | No transfer pagination cursors | +| B-039 | 🟡 Medium | backend/api | Investment withdrawal list lacks pagination | +| B-040 | 🟢 Low | backend/api | Government list `limit` NaN hazard | +| B-041 | 🟢 Low | backend/types | Prisma `onRampSwap` typed via `as any` casts | +| B-042 | 🟡 Medium | backend/webhooks | Webhook raw body JSON fallback empty object | +| B-043 | 🟢 Low | backend/notifications | Notification service placeholder sender | +| B-044 | 🟡 Medium | backend/ops | Basket weight computation job missing | +| B-045 | 🟡 Medium | backend/integrations | Fintech multi-provider per country | +| B-046 | 🟢 Low | backend/config | Limits config hardcoded | +| B-047 | 🟡 Medium | backend/authz | Segment guard `requireMinTier` unused | +| B-048 | 🟢 Low | backend/types | Permissions typed as loose strings | +| B-049 | 🟠 High | backend/security | CORS policy review for credentialed browsers | +| B-050 | 🟡 Medium | backend/security | Helmet / security headers baseline | +| B-051 | 🟢 Low | backend/observability | Request ID propagation | +| B-052 | 🟡 Medium | backend/observability | Structured logging for money movements | +| B-053 | 🟠 High | backend/api | Idempotency-Key header support | +| B-054 | 🟢 Low | backend/observability | Distributed tracing (OpenTelemetry) | +| B-055 | 🟡 Medium | backend/ci | Database migration CI gate | +| B-056 | 🟡 Medium | backend/config | Prisma Accelerate vs direct URL confusion | +| B-057 | 🟢 Low | backend/data | Mongo index strategy for hot keys | +| B-058 | 🟡 Medium | backend/compliance | Encryption at rest for PII columns | +| B-059 | 🟡 Medium | backend/compliance | GDPR export & delete endpoints | +| B-060 | 🟠 High | backend/authz | Admin role separation | +| B-061 | 🟠 High | backend/config | Secrets in environment validation | +| B-062 | 🟡 Medium | backend/storage | S3 presigned URL abuse controls | +| B-063 | 🟡 Medium | backend/ai | OpenAI usage guardrails | +| B-064 | 🟡 Medium | backend/security | Dependency vulnerability scanning | +| B-065 | 🟢 Low | backend/auth | Time sync / clock skew handling for JWT | +| B-066 | 🟡 Medium | backend/auth | 2FA challenge token purpose binding | +| B-067 | 🟡 Medium | backend/auth | Account enumeration on sign-in | +| B-068 | 🟠 High | backend/auth | Brute-force protection on auth endpoints | +| B-069 | 🟡 Medium | backend/security | Content-Type and body size limits | +| B-070 | 🟢 Low | backend/api | Input sanitization for search endpoints | +| B-071 | 🟢 Low | backend/api | Versioning and deprecation headers | +| B-072 | 🟡 Medium | backend/api | Consistent error JSON schema | +| B-073 | 🟠 High | backend/core | Transaction status machine tests | +| B-074 | 🟡 Medium | backend/burn | Double-submit burn with same blockchain hash | +| B-075 | 🟠 High | backend/jobs | On-ramp swap race: duplicate processing | + +**Totals:** 2 Critical · 21 High · 38 Medium · 14 Low · **75 total catalog items** (all IDs `B-001` through `B-075`, fully aligned with `issues/backend.md`). + +--- + +## 2. Severity Counts + +| Severity | Count | +|----------|-------| +| 🔴 Critical | **2** (B-005, B-006) | +| 🟠 High | **21** (B-001–B-004, B-007–B-011, B-013, B-016, B-017, B-026, B-028, B-049, B-053, B-060, B-061, B-068, B-073, B-075) | +| 🟡 Medium | **38** (B-012, B-014, B-015, B-018–B-025, B-027, B-029, B-031, B-033, B-034, B-036–B-039, B-042, B-044, B-045, B-047, B-050, B-052, B-055, B-056, B-058, B-059, B-062–B-064, B-066, B-067, B-069, B-072, B-074) | +| 🟢 Low | **14** (B-030, B-032, B-035, B-040, B-041, B-043, B-046, B-048, B-051, B-054, B-057, B-065, B-070, B-071) | +| **Total** | **75** | + +--- + +## 3. Critical Issues (🔴) — Ship Blockers + +### B-005 — Webhook signature verification fail-open risk +- **Area:** backend/webhooks +- **Evidence:** `acbu-backend/src/controllers/webhookController.ts` / `verifyFlutterwaveSignature` (verify pattern) +- **Impact:** If `FLUTTERWAVE_WEBHOOK_SECRET` (or equivalent secrets) are missing in production, verification is skipped and `next()` is called, allowing forged webhooks to mint credit downstream. +- **Fix direction:** Fail closed in production when secret env vars are missing; separate dev/stage mocks; refuse to register the webhook route in prod without a usable secret. +- **Acceptance check:** Production boot fails fast (or webhook handlers return 401) when signing secret is unset; staging retains the mocked-verify behavior under a feature flag. + +### B-006 — Recovery unlock as single-factor account recovery +- **Area:** backend/auth +- **Evidence:** `acbu-backend/src/services/recovery/recoveryService.ts` (per prior audits) +- **Impact:** Identifier + passcode alone can issue a new API key; a leaked/stolen passcode enables full account takeover. +- **Fix direction:** Add OTP (email/SMS) and/or device proof as a second factor; rate-limit recovery endpoints; rotate all existing sessions on success; emit audit event. +- **Acceptance check:** E2E test confirms a fresh API key cannot be obtained without the configured second factor; brute-force lockout kicks in after threshold. + +--- + +## 4. High Severity Issues (🟠) + +### B-001 — Mint basket deposit limits use wrong USD proxy +- **Area:** backend/minting +- **Evidence:** `acbu-backend/src/controllers/mintController.ts` (`depositFromBasketCurrency`) +- **Impact:** Local currency amounts are treated as USD when calling `checkDepositLimits`; limits can be wildly wrong for NGN/KES/etc. +- **Fix direction:** Convert basket currency → USD using oracle/rates before limit checks; populate per-basket limit constants from config. +- **Acceptance check:** Integration tests for each basket currency enforce the correct USD-denominated limits. + +### B-002 — Floating `Number()` on money paths +- **Area:** backend/money +- **Evidence:** Multiple controllers (`mintController.ts`, `burnController.ts`) +- **Impact:** `Number()` over user-supplied monetary strings loses precision versus `Decimal` and can skew fee/limit math. +- **Fix direction:** Parse monetary strings with a decimal library end-to-end; coerce to `Decimal` at every model boundary; only lossy coerce at the Soroban boundary with explicit rounding policy. +- **Acceptance check:** Golden tests for large fractional inputs and boundary fees pass. + +### B-003 — USDC convert job infinite requeue on failure +- **Area:** backend/jobs +- **Evidence:** `acbu-backend/src/jobs/usdcConvertAndMintJob.ts` (`ch.nack(..., true)`) +- **Impact:** Poison messages can spin forever, duplicating side effects or stalling the queue; `OnRampSwap` rows never reach terminal state. +- **Fix direction:** Add retry caps + DLQ routing; transition `OnRampSwap.status` atomically to `failed` after N attempts with the failure reason. +- **Acceptance check:** Failed swap lands in DLQ; corresponding DB row reaches terminal state; no infinite nack loop under chaos replay. + +### B-004 — Webhook delivery retry semantics +- **Area:** backend/webhooks +- **Evidence:** `acbu-backend/src/services/webhook/webhookService.ts` +- **Impact:** Partners may be hammered; events retried without idempotency can cause duplicate settlements. +- **Fix direction:** Per-delivery idempotency keys; exponential backoff; max attempts; DLQ + alerting on sustained failure. +- **Acceptance check:** Webhook consumer stops after configured failure threshold; DLQ is observable in the ops dashboard. + +### B-007 — Client-supplied mint recipient vs user wallet +- **Area:** backend/minting +- **Evidence:** `acbu-backend/src/controllers/mintController.ts`, on-ramp controllers +- **Impact:** If mint / on-ramp paths still accept a body-supplied `wallet_address` without binding to `User.stellarAddress`, minted ACBU can be redirected to an unrelated address. +- **Fix direction:** Centralize `assertUserWalletAddress` on every mint / on-ramp path; deny mismatches with a structured 403. +- **Acceptance check:** Security test fails when minting to a `G…` not owned by the authenticated user. + +### B-008 — Transfer service Decimal typing +- **Area:** backend/transfers +- **Evidence:** `acbu-backend/src/services/transfer/transferService.ts` +- **Impact:** String amounts into Prisma Decimal fields risk precision and type drift at runtime. +- **Fix direction:** Construct `Decimal` explicitly; validate with Zod (`string` + decimal regex) before passing to Prisma. +- **Acceptance check:** Unit tests pass for maximum-precision transfers and boundary cases. + +### B-009 — Burn fee policy threshold logic +- **Area:** backend/fees +- **Evidence:** `acbu-backend/src/services/feePolicy/feePolicyService.ts` +- **Impact:** Suspected inverted/typo thresholds can charge wrong BPS versus the reserve basket state. +- **Fix direction:** Review the math against `OPERATIONS/LIMITS_AND_TIERS` and product spec; add property tests for the published tier table. +- **Acceptance check:** Fee outputs match the documented tier table for all bracket boundaries. + +### B-010 — ReserveTracker total supply from DB not chain +- **Area:** backend/reserves +- **Evidence:** `acbu-backend/src/services/reserve/ReserveTracker.ts` +- **Impact:** On-chain supply and indexed DB can diverge; circuit breakers may compute against the wrong numerator. +- **Fix direction:** Periodic chain-truth reconciliation; alert on drift beyond policy threshold. +- **Acceptance check:** Dashboard surfaces DB vs on-chain delta under threshold; sustained drift alerts. + +### B-011 — Org-scoped transaction limits with null userId +- **Area:** backend/limits +- **Evidence:** `acbu-backend/src/services/limits/limitsService.ts` +- **Impact:** Org keys creating `userId: null` rows may be excluded from aggregates; limits can be bypassed at the org level. +- **Fix direction:** Include `organizationId` dimension consistently in limit queries; align with the prisma `Transaction` schema. +- **Acceptance check:** Org-scope key cannot exceed org daily cap in tests. + +### B-013 — Placeholder / invalid Stellar address on signup +- **Area:** backend/auth +- **Evidence:** `acbu-backend/src/services/auth/authService.ts` (`getPlaceholderStellarAddress`) +- **Impact:** Non-`G` placeholders break downstream Stellar validation and break UX. +- **Fix direction:** Defer the DB constraint until the real wallet is created, **or** use a valid funded temporary account pattern under a feature flag. +- **Acceptance check:** No user row ships in production with an invalid `stellarAddress` format. + +### B-016 — Stellar event listener scope and error handling +- **Area:** backend/stellar +- **Evidence:** `acbu-backend/src/services/stellar/eventListener.ts` +- **Impact:** Broad Horizon streams + swallowed errors cause missed mint/burn indexing silently. +- **Fix direction:** Filter to known contract IDs; structured retries; DLQ routing for parse failures; metrics on event ingestion lag. +- **Acceptance check:** Injected test event reaches projection store within SLA under simulated outages. + +### B-017 — KYC machine layer is placeholder +- **Area:** backend/kyc +- **Evidence:** `acbu-backend/src/services/kyc/machineLayer.ts` +- **Impact:** Automated checks / PII redaction are not production-grade; KYC fraud risk increases. +- **Fix direction:** Integrate a vision provider; PII redaction pipeline; manual review queue for low-confidence results. +- **Acceptance check:** Sample IDs pass/fail deterministically in staging with redacted logs. + +### B-026 — Audit write failures only logged +- **Area:** backend/audit +- **Evidence:** `acbu-backend/src/services/audit/auditService.ts` +- **Impact:** Compliance gap if audit events disappear silently. +- **Fix direction:** Retry + outbox to Mongo/queue; sustained-failure alert; dashboard on audit lag. +- **Acceptance check:** Chaos test (simulated Mongo/queue outage) demonstrates the audit pipeline recovers and reaches eventual consistency. + +### B-028 — API key rate limiter non-atomic increment +- **Area:** backend/ratelimit +- **Evidence:** `acbu-backend/src/middleware/rateLimiter.ts` +- **Impact:** Get-then-set increment pattern is not atomic; concurrent requests can both pass the limit. +- **Fix direction:** Use Mongo atomic `$inc` with a per-key document-level cap **or** Redis `INCR` with TTL. +- **Acceptance check:** Concurrent load test cannot exceed configured QPS for any single API key. + +### B-049 — CORS policy review for credentialed browsers +- **Area:** backend/security +- **Evidence:** `acbu-backend/src/index.ts` / CORS config +- **Impact:** Misconfigured origins with credentials enable token theft via malicious site. +- **Fix direction:** Explicit allowlist per environment; never combine `*` with `credentials: true`. +- **Acceptance check:** Security headers test suite (OWASP baseline) passes. + +### B-053 — Idempotency-Key header support +- **Area:** backend/api +- **Evidence:** POST transfer/mint/burn routes +- **Impact:** Network retries can double-charge / double-mint. +- **Fix direction:** Persist keys in `Idempotency` table; cache and return identical response bodies for repeated keys. +- **Acceptance check:** Duplicate POST with the same key returns the cached response within the configured TTL. + +### B-060 — Admin role separation +- **Area:** backend/authz +- **Evidence:** Admin vs user API keys +- **Impact:** Support-staff impersonation is overpowered; single admin key compromise is catastrophic. +- **Fix direction:** Scoped admin keys + MFA + break-glass workflow; attribute admin actions separately in audit. +- **Acceptance check:** Admin actions are clearly delineated in audit; scoped keys cannot perform unscoped operations. + +### B-061 — Secrets in environment validation +- **Area:** backend/config +- **Evidence:** `acbu-backend/src/config/env.ts` +- **Impact:** Late or partial validation lets half-configured prod boot. +- **Fix direction:** Strict Zod schema at startup with `fail-fast`; no `config` access before validation runs. +- **Acceptance check:** Missing `JWT_SECRET` (or any required secret) prevents the process from `app.listen`. + +### B-068 — Brute-force protection on auth endpoints +- **Area:** backend/auth +- **Evidence:** `authRoutes` + rate limiter +- **Impact:** Passcodes / API keys are guessable at scale. +- **Fix direction:** Stricter limiter on `/auth/*`; explicit lockout policy; backoff. +- **Acceptance check:** Hydra-style test is blocked after configured threshold. + +### B-073 — Transaction status machine tests +- **Area:** backend/core +- **Evidence:** Prisma `Transaction` model transitions +- **Impact:** Illegal transitions corrupt balance reporting. +- **Fix direction:** Explicit state machine + DB constraints; property tests covering every transition pair. +- **Acceptance check:** Invalid transition throws a domain error and is also rejected by a DB-level `CHECK` constraint. + +### B-075 — On-ramp swap race: duplicate processing +- **Area:** backend/jobs +- **Evidence:** `acbu-backend/src/jobs/usdcConvertAndMintJob.ts` (`OnRampSwap.status` transitions) +- **Impact:** Two workers may pick the same `pending` swap if the status check is non-atomic. +- **Fix direction:** Use conditional update `WHERE status = 'pending'` to transition to `processing`, scoped by id; verification in concurrency tests. +- **Acceptance check:** Concurrency test confirms exactly one worker processes each swap. + +--- + +## 5. Medium Severity Issues (🟡) + +### B-012 — Savings controller input validation +- **Area:** backend/savings · **Evidence:** `acbu-backend/src/controllers/savingsController.ts` +- **Impact:** `amount` / `term_seconds` unchecked before contract calls; bad Soroban args or cryptic errors. +- **Fix direction:** Zod schemas with bounds; decimal-string amount; reject overflow before service dispatch. +- **Acceptance check:** Invalid bodies produce structured 400 errors; valid bodies pass service-layer validation. + +### B-014 — Wallet activation funding asset choice +- **Area:** backend/wallet · **Evidence:** `acbu-backend/src/services/wallet/walletActivationService.ts` +- **Impact:** Product docs reference Pi vs XLM; wrong asset strands users on the wrong network. +- **Fix direction:** Align with `TESTNET_CUSTODIAL_BOOTSTRAP` / network config; expose a network-scoped feature flag; clear log of chosen asset. +- **Acceptance check:** Activation succeeds on the configured network with the documented asset. + +### B-015 — Hardcoded Soroban inclusion fees +- **Area:** backend/stellar · **Evidence:** `acbu-backend/src/services/stellar/contractClient.ts` and related services +- **Impact:** Default fee `'100'` may fail under network congestion or be overpaid; confirmation timing is unpredictable. +- **Fix direction:** Fetch base fee + soroban resource fees via Horizon / RPC; configurable caps. +- **Acceptance check:** Transactions succeed under load tests with no manual fee intervention. + +### B-018 — Government treasury aggregation stub +- **Area:** backend/government · **Evidence:** `acbu-backend/src/controllers/governmentController.ts` +- **Impact:** Operators lack a consolidated exposure view. +- **Fix direction:** Aggregate from Prisma + reserve segments; cache with TTL; populate per-currency breakdown. +- **Acceptance check:** Endpoint returns non-empty `byCurrency` against seeded data. + +### B-019 — Salary APIs not implemented +- **Area:** backend/salary · **Evidence:** `acbu-backend/src/controllers/salaryController.ts` +- **Impact:** MVP payroll promises are unfulfilled; clients get 501/empty arrays. +- **Fix direction:** Batch transfers + schedules + idempotency keys; reuse `transferService` for the core accounting. +- **Acceptance check:** Postman collection green for happy path. + +### B-020 — Enterprise bulk transfer not implemented +- **Area:** backend/enterprise · **Evidence:** `acbu-backend/src/controllers/enterpriseController.ts` +- **Impact:** Large merchants cannot upload batches. +- **Fix direction:** Chunked processing; per-row idempotency; reporting endpoint for partial failure. +- **Acceptance check:** 10k-row CSV completes within SLO with a partial-failure report. + +### B-021 — Enterprise treasury view stub +- **Area:** backend/enterprise · **Evidence:** `acbu-backend/src/controllers/enterpriseController.ts` (`getTreasury`) +- **Impact:** Treasury nulls block finance workflows. +- **Fix direction:** Join transfers, reserves, FX snapshots. +- **Acceptance check:** Totals reconcile to ledger within tolerance. + +### B-022 — Bills catalog and pay not implemented +- **Area:** backend/bills · **Evidence:** `acbu-backend/src/controllers/billsController.ts` +- **Impact:** Bill-pay segment is non-functional. +- **Fix direction:** Partner adapter + webhook reconciliation + refund flow. +- **Acceptance check:** Happy-path bill payment creates an auditable `Transaction`. + +### B-023 — Investment deployable allocation ignores deployed +- **Area:** backend/investment · **Evidence:** `acbu-backend/src/services/investment/allocationService.ts` +- **Impact:** `deployedUsd` pinned to 0 over-allocates to strategies. +- **Fix direction:** Track deployed notional in DB; subtract from deployable; tie ledger adjustments to allocation events. +- **Acceptance check:** Allocation never exceeds policy once deployed balances are populated. + +### B-024 — Investment withdrawal notifications for org requests +- **Area:** backend/jobs · **Evidence:** `acbu-backend/src/jobs/investmentWithdrawalJob.ts` +- **Impact:** Org-only requests may never notify approvers. +- **Fix direction:** Notify org admins via email/push using `organizationId`; mirror for org-only `r.organizationId` rows where `r.userId` is null. +- **Acceptance check:** Org withdrawal request lands a notification in the test inbox. + +### B-025 — Yield accounting stub +- **Area:** backend/investment · **Evidence:** `acbu-backend/src/services/investment/yieldAccountingService.ts` +- **Impact:** Cannot report yield or tax basis. +- **Fix direction:** Implement accrual postings tied to vault positions; statement API endpoint. +- **Acceptance check:** Monthly statement API returns non-zero yield against seeded positions. + +### B-027 — Cache `deletePattern` ReDoS risk +- **Area:** backend/cache · **Evidence:** `acbu-backend/src/utils/cache.ts` +- **Impact:** User-influenced regex patterns can hang the Node event loop. +- **Fix direction:** Escape / length-cap patterns; prefer safe glob or prefix scan instead of arbitrary regex. +- **Acceptance check:** Fuzz test cannot stall the event loop beyond budget. + +### B-029 — Rate limiter Mongo outage fail-open +- **Area:** backend/ratelimit · **Evidence:** `acbu-backend/src/middleware/rateLimiter.ts` + `cacheService` +- **Impact:** When cache errors, fallback may weaken per-key limits. +- **Fix direction:** Stricter IP fallback + circuit breaker + active metrics on degraded mode. +- **Acceptance check:** Simulated Mongo outage triggers the documented degraded-but-bounded mode. + +### B-031 — Deep health and metrics routes are public +- **Area:** backend/ops · **Evidence:** `acbu-backend/src/routes/index.ts` (`/health/deep`, `/health/metrics`) +- **Impact:** Dependency topology exposes to unauthenticated callers (reconnaissance). +- **Fix direction:** Protect with mTLS or admin API key; keep `/health` shallow public. +- **Acceptance check:** Public callers cannot scrape dependency failures or reserve ratios at scale. + +### B-033 — Swagger UI publicly mounted +- **Area:** backend/docs · **Evidence:** `acbu-backend/src/index.ts` +- **Impact:** Attackers map the surface area without auth. +- **Fix direction:** Gate `/api-docs` behind admin auth, or disable in prod. +- **Acceptance check:** Prod deployment returns 404 (or admin-authenticated response) for `/api-docs`. + +### B-034 — OpenAPI drift vs implementation +- **Area:** backend/docs · **Evidence:** `acbu-backend` swagger annotations vs routes +- **Impact:** Clients integrate against stale schemas. +- **Fix direction:** CI check: generate OpenAPI + contract tests against Zod schemas; block merges on drift. +- **Acceptance check:** CI fails when a route removes a field still documented (or adds a field undocumented). + +### B-036 — `postinstall` runs `prisma generate` + `tsc` +- **Area:** backend/devx · **Evidence:** `acbu-backend/package.json` (`postinstall`) +- **Impact:** Slow installs; CI surprises; failures on restricted networks. +- **Fix direction:** Move TypeScript compile to an explicit CI step; keep `postinstall` to `prisma generate` only. +- **Acceptance check:** `pnpm install <2 min` on a clean cache (target); CI has a deterministic compile step. + +### B-037 — Jest `passWithNoTests` weak gate +- **Area:** backend/qa · **Evidence:** `acbu-backend/package.json` (`test` script) +- **Impact:** Missing tests do not fail CI. +- **Fix direction:** Remove the flag once smoke tests exist; require minimum coverage thresholds in money modules. +- **Acceptance check:** CI fails if no tests under `src/services/transfer` (or other money-present paths). + +### B-038 — No transfer pagination cursors +- **Area:** backend/api · **Evidence:** `acbu-backend/src/controllers/transferController.ts` +- **Impact:** Clients cannot paginate beyond the first 50. +- **Fix direction:** Cursor pagination + composite index on `(userId, createdAt)`. +- **Acceptance check:** Client walks entire history without duplicates. + +### B-039 — Investment withdrawal list lacks pagination +- **Area:** backend/api · **Evidence:** `acbu-backend/src/controllers/investmentController.ts` +- **Impact:** Same 50-row cap as transfers. +- **Fix direction:** Cursor + filters by status; matching DB index. +- **Acceptance check:** Large org history loads progressively. + +### B-042 — Webhook raw body JSON fallback empty object +- **Area:** backend/webhooks · **Evidence:** `acbu-backend/src/index.ts` +- **Impact:** Invalid JSON becomes `{}`; handlers may run on bad data. +- **Fix direction:** Reject non-JSON with 400 before routing; fail closed. +- **Acceptance check:** Malformed payload raises a 400 and never reaches business logic. + +### B-044 — Basket weight computation job missing +- **Area:** backend/ops · **Evidence:** Documented in `PROJECT/issues/BACKEND_ISSUES.md` +- **Impact:** Weights drift from policy without automation. +- **Fix direction:** Scheduled job (`metricsService`/`proposedWeightsJob`) + audit log + manual approval gate. +- **Acceptance check:** Weekly job emits a diff report against the active basket config. + +### B-045 — Fintech multi-provider per country +- **Area:** backend/integrations · **Evidence:** `acbu-backend` webhook + payout modules +- **Impact:** Single Flutterwave path = outage risk. +- **Fix direction:** Router chooses provider by health + fees + country per `correction.md` (e.g. NGN: Paystack + Flutterwave). +- **Acceptance check:** Simulated provider outage fails over; both providers exercised in tests. + +### B-047 — Segment guard `requireMinTier` unused +- **Area:** backend/authz · **Evidence:** `acbu-backend/src/middleware/segmentGuard.ts` +- **Impact:** `User.tier` field unused → wrong product gating at the middleware layer. +- **Fix direction:** Apply middleware to premium routes; add tests for tier-bound routes. +- **Acceptance check:** Free-tier user cannot call SME-only endpoints in tests. + +### B-050 — Helmet / security headers baseline +- **Area:** backend/security · **Evidence:** `acbu-backend/src/index.ts` +- **Impact:** Missing headers increase XSS/clickjacking risk. +- **Fix direction:** Helmet defaults + CSP for any server-rendered/static content; documented exceptions. +- **Acceptance check:** `securityheaders.io` reports no worse than `A-` (or documented exceptions). + +### B-052 — Structured logging for money movements +- **Area:** backend/observability · **Evidence:** `acbu-backend/src/config/logger.ts` usage +- **Impact:** Insufficient fields for forensic audit (amount, currency, user, idempotency key). +- **Fix direction:** Standard log schema for financial events. +- **Acceptance check:** Log query returns the full transfer lifecycle by user/idempotency key. + +### B-055 — Database migration CI gate +- **Area:** backend/ci · **Evidence:** `.github/workflows` +- **Impact:** Destructive migrations ship without warning. +- **Fix direction:** Ensure `prisma migrate diff` or deploy dry-run in CI; require label for destructive migrations. +- **Acceptance check:** CI fails on destructive migration without the required label. + +### B-056 — Prisma Accelerate vs direct URL confusion +- **Area:** backend/config · **Evidence:** `acbu-backend/README.md` + `ENV_VARS.md` +- **Impact:** Wrong URL used for migrations vs runtime. +- **Fix direction:** Document matrix; startup assert roles. +- **Acceptance check:** Boot logs show correct URL type per purpose. + +### B-058 — Encryption at rest for PII columns +- **Area:** backend/compliance · **Evidence:** `prisma/schema.prisma` +- **Impact:** DB leak exposes plaintext government IDs. +- **Fix direction:** App-level encryption or DB TDE; KMS rotation; documented key management. +- **Acceptance check:** Security review sign-off for the chosen field list and key lifecycle. + +### B-059 — GDPR export & delete endpoints +- **Area:** backend/compliance · **Evidence:** User settings (verify coverage) +- **Impact:** Regulatory exposure for EU users. +- **Fix direction:** Data export job + tombstone deletes; documented legal data categories. +- **Acceptance check:** DPO checklist satisfied; sample export contains only documented fields. + +### B-062 — S3 presigned URL abuse controls +- **Area:** backend/storage · **Evidence:** KYC uploads (if S3) +- **Impact:** Open buckets / long TTL enable exfiltration. +- **Fix direction:** Short TTL + content-type constraint + virus scan hook. +- **Acceptance check:** Pen test cannot read other users' KYC objects. + +### B-063 — OpenAI usage guardrails +- **Area:** backend/ai · **Evidence:** `package.json` includes `openai` +- **Impact:** Prompt injection or runaway spend. +- **Fix direction:** Auth + per-org budget + prompt allowlist; spend alerts. +- **Acceptance check:** Spending caps enforced in staging load test. + +### B-064 — Dependency vulnerability scanning +- **Area:** backend/security · **Evidence:** `pnpm-lock.yaml` +- **Impact:** Known CVEs in transitive deps. +- **Fix direction:** Enable Dependabot/Snyk + monthly cadence. +- **Acceptance check:** CI fails on critical CVE without an explicit waiver label. + +### B-066 — 2FA challenge token purpose binding +- **Area:** backend/auth · **Evidence:** `acbu-backend/src/utils/jwt.ts` +- **Impact:** Reuse across flows if `aud`/`iss` checks incomplete. +- **Fix direction:** Add `aud`/`iss` claims; rotate secrets. +- **Acceptance check:** Challenge token cannot be used as a general API token. + +### B-067 — Account enumeration on sign-in +- **Area:** backend/auth · **Evidence:** `acbu-backend/src/controllers/auth.ts` (verify responses) +- **Impact:** Attackers learn which emails exist via timing / response differences. +- **Fix direction:** Uniform error messages; CAPTCHA after N tries; throttling; normalize timing. +- **Acceptance check:** Timing differences and message differences are below the noise threshold. + +### B-069 — Content-Type and body size limits +- **Area:** backend/security · **Evidence:** Express JSON parser +- **Impact:** Large JSON DoS. +- **Fix direction:** Lower default limit; per-route overrides for upload endpoints. +- **Acceptance check:** 10MB payload rejected where inappropriate. + +### B-072 — Consistent error JSON schema +- **Area:** backend/api · **Evidence:** `errorHandler.ts` vs legacy `{ error: string }` +- **Impact:** Frontend parsing brittle. +- **Fix direction:** Standard envelope `{ error: { code, message, details } }` everywhere. +- **Acceptance check:** OpenAPI examples match runtime errors. + +### B-074 — Double-submit burn with same blockchain hash +- **Area:** backend/burn · **Evidence:** `burnController.ts` optional `blockchain_tx_hash` +- **Impact:** Replay duplicates redemption records. +- **Fix direction:** Unique index on hash when present + idempotency-key handling. +- **Acceptance check:** Second submit returns the original id; no duplicate row created. + +--- + +## 6. Low Severity Issues (🟢) + +### B-030 — Standard IP rate limit message mismatch +- **Area:** backend/ratelimit · **Evidence:** `acbu-backend/src/middleware/rateLimiter.ts` (`createRateLimiter`) +- **Impact:** Message says “IP” while some routes use API keys. +- **Fix direction:** Contextual messages; separate limiters. +- **Acceptance check:** 429 JSON explains which limit tripped. + +### B-032 — Shallow `/health` does not prove readiness +- **Area:** backend/ops · **Evidence:** `acbu-backend/src/routes/index.ts` (`/health`) +- **Impact:** LB marks instance ready while DB/queue is down. +- **Fix direction:** Optional `/health/ready` for k8s; document split. +- **Acceptance check:** K8s readiness uses the deep check when configured. + +### B-035 — README still references npm only +- **Area:** backend/devx · **Evidence:** `acbu-backend/README.md` +- **Impact:** Contributors mix npm/pnpm; lockfile drift. +- **Fix direction:** Document pnpm as canonical; align scripts. +- **Acceptance check:** Single package manager in README + CI. + +### B-040 — Government list `limit` NaN hazard +- **Area:** backend/api · **Evidence:** `acbu-backend/src/controllers/governmentController.ts` +- **Impact:** `Number(NaN)` can break Prisma `take`/`skip`. +- **Fix direction:** Zod coerce int with min/max defaults. +- **Acceptance check:** Invalid limit returns 400 with structured error. + +### B-041 — Prisma `onRampSwap` typed via `as any` casts +- **Area:** backend/types · **Evidence:** Jobs/controllers casting prisma client +- **Impact:** Hides compile-time safety for financial rows. +- **Fix direction:** Regenerate client; fix schema naming; remove casts. +- **Acceptance check:** No `(prisma as any)` in `src/jobs`. + +### B-043 — Notification service placeholder sender +- **Area:** backend/notifications · **Evidence:** `acbu-backend/src/services/notification/notificationService.ts` +- **Impact:** Emails may bounce or hit spam. +- **Fix direction:** Configure SES/SendGrid with verified domain; DKIM/SPF green. +- **Acceptance check:** DNS DKIM/SPF green in staging; smoke test delivers to a known inbox. + +### B-046 — Limits config hardcoded +- **Area:** backend/config · **Evidence:** `acbu-backend/src/config/limits.ts` +- **Impact:** Ops cannot tune without redeploy. +- **Fix direction:** Load from DB or env with hot reload cache. +- **Acceptance check:** Limit change applies without redeploy. + +### B-048 — Permissions typed as loose strings +- **Area:** backend/types · **Evidence:** `acbu-backend/src/middleware/auth.ts` (`validatePermissions`) +- **Impact:** Typos in DB JSON grant wrong access. +- **Fix direction:** Zod enum list for permissions at write time. +- **Acceptance check:** Invalid permission rejected at admin API. + +### B-051 — Request ID propagation +- **Area:** backend/observability · **Evidence:** Express middleware stack +- **Impact:** Hard to correlate user reports with logs. +- **Fix direction:** Add `x-request-id` middleware; log field; pass through downstream calls. +- **Acceptance check:** Support engineers can trace a single request across services end-to-end. + +### B-054 — Distributed tracing (OpenTelemetry) +- **Area:** backend/observability · **Evidence:** N/A +- **Impact:** Cross-service latency is opaque. +- **Fix direction:** OTel exporter with sample rates; per-route overrides. +- **Acceptance check:** Trace links Prisma + Soroban submit span under load. + +### B-057 — Mongo index strategy for hot keys +- **Area:** backend/data · **Evidence:** Mongo collections for cache/ratelimit +- **Impact:** Hot keys slow under load. +- **Fix direction:** Index design review + TTL policies. +- **Acceptance check:** Load-test p95 under SLO; TTL confirmed for ephemeral collections. + +### B-065 — Time sync / clock skew handling for JWT +- **Area:** backend/auth · **Evidence:** `acbu-backend/src/utils/jwt.ts` +- **Impact:** Skew causes confusing 401s. +- **Fix direction:** Leeway config + NTP monitoring; document skew tolerance. +- **Acceptance check:** Clock-skew test passes within the documented window. + +### B-070 — Input sanitization for search endpoints +- **Area:** backend/api · **Evidence:** Recipient resolve / user search +- **Impact:** SQL/NoSQL injection via regex. +- **Fix direction:** Parameterized queries only; escape user-supplied regex. +- **Acceptance check:** Security scanner reports clean for all recipient/user search paths. + +### B-071 — Versioning and deprecation headers +- **Area:** backend/api · **Evidence:** `config.apiVersion` +- **Impact:** Clients stuck on breaking changes. +- **Fix direction:** `Sunset` header + changelog endpoint. +- **Acceptance check:** Old API version returns the warning header and changelog link. + +--- + +## 7. Legacy 56-Item Origin List (cross-reference) + +The legacy list previously alone at this path was a more recent manual audit with slightly different framing. Items are preserved here for traceability; each is tagged `(moved)` (when it cleanly maps to a canonical `B-###` ID) or `(new)` (when it captures a distinct finding that should be merged into the canonical list in a follow-up PR). + +### Critical +1. **API key validation broken** – src/middleware/auth.ts: `validateApiKey` uses `bcrypt.hash` for lookup (random salt) → stored hash never matches. Use `bcrypt.compare`. **Distinct finding; not in the canonical 75-item list. Should be promoted to a follow-up canonical ID (expected `B-076`) in a separate PR.** *(new — propose B-076)* +2. **Wrong import in `usdcConvertAndMintJob`** – Imports `db` from `../config/database` but module exports `prisma`. **Maps to a runtime variant of B-003 / B-075; tracked together.** *(moved → B-003 + B-075)* +3. **IDOR / auth bypass in savings controller** – `user` taken from body/query, not authenticated user. **Combine with B-007 + segment guards.** *(moved → B-007)* +4. **Env validation too late** – `requiredEnvVars` checked after `config` is built. **Folds into B-061.** *(moved → B-061)* + +### High +5. **Infinite retries for failed webhooks** – *(moved → B-004)* +6. **Organization users never notified for investment withdrawal** – *(moved → B-024)* +7. **Burn limits bypass when `audience` is unset** – Mirror B-007 in the burn path. **Folds into B-005 / B-007 / B-009 audit.** *(moved → B-007 + B-009)* +8. **Mint limits bypass when `audience` is unset** – Same root cause as #7. *(moved → B-007 + B-001)* +9. **Fee thresholds likely wrong** – *(moved → B-009)* +10. **Decimal vs string for `acbuAmount` in transfer** – *(moved → B-008)* +11. **No dead-letter queues** – Folds into B-003, B-004, B-026. *(moved → B-003 + B-004)* +12. **No max retry limit for webhook consumer** – Folds into B-003, B-004, B-026. *(moved → B-004)* + +### Medium +13. **Wallet activation uses XLM, not Pi** – *(moved → B-014)* +14. **Remove placeholder Stellar address in auth** – *(moved → B-013)* +15. **Transfer service: verify alias-based flow** – Folds into B-007 + B-008. *(moved → B-007 + B-008)* +16. **Contract client and Stellar fees hardcoded** – *(moved → B-015)* +17. **Multiple fintech providers per nation** – *(moved → B-045)* (also reinforced by `correction.md`) +18. **KYC extraction placeholder** – *(moved → B-017)* +19. **Basket weight script missing** – *(moved → B-044)* +20. **Balance endpoint for frontend missing** – Cross-cutting concern surfaced in `issues/frontend.md` `F-025`; see **Cross-Reference Map**. *(new — cross-cutting)* +21. **No dependency health checks** – Reinforces B-031 / B-032. *(moved → B-031 + B-032)* +22. **Race condition in API key rate limiting** – *(moved → B-028)* +23. **ReDoS risk in `deletePattern`** – *(moved → B-027)* +24. **Webhook verification skipped when secret missing** – *(moved → B-005)* +25. **Placeholder Stellar address format invalid** – *(moved → B-013)* +26. **ACBU supply from DB, not chain** – *(moved → B-010)* +27. **Org-scoped limits may not apply** – *(moved → B-011)* +28. **USDC to XLM conversion is a no-op** – *(moved → B-003 + B-075)* +29. **Hardcoded XLM rate** – *(moved → B-002 + B-015)* +30. **Deposit limits use wrong USD equivalent** – *(moved → B-001)* +31. **Incomplete treasury aggregation** – *(moved → B-018)* +32. **Audit failures are silent** – *(moved → B-026)* + +### Low +33. **`any` cast for permissions** – *(moved → B-048)* +34. **`any` usage in segmentGuard** – *(moved → B-047 + B-048)* +35. **`any` usage in Stellar client** – *(moved → B-041)* +36. **`any` cast in burning service** – *(moved → B-041)* +37. **No pagination on transfers** – *(moved → B-038)* +38. **No pagination on investment withdrawals** – *(moved → B-039)* +39. **`limit` query param not validated** – *(moved → B-040)* +40. **No input validation in savings controller** – *(moved → B-012)* +41. **Missing composite index** – Tied to B-038 / B-039. *(moved → B-038 + B-039)* +42. **Webhook JSON parse failure returns empty body** – *(moved → B-042)* +43. **Stack traces in error logs** – Cross-cutting; folded into B-051 / B-052 + a structured error envelope (B-072). *(moved → B-051 + B-052 + B-072)* + +### Trivial +44. **`(prisma as any).onRampSwap` casts** – *(moved → B-041)* +45. **Hardcoded limit values** – *(moved → B-046)* +46. **Fallback email placeholder** – *(moved → B-043)* +47. **Yield accounting stub** – *(moved → B-025)* +48. **No automated tests** – *(moved → B-037)* + general backend hygiene +49. **Client-controlled mint recipient** – *(moved → B-007)* +50. **Rate limiting fails open when MongoDB cache is down** – *(moved → B-029)* +51. **Recovery unlock is single-factor** – *(moved → B-006)* +52. **`requireMinTier` middleware is never used** – *(moved → B-047)* +53. **`InvestmentWithdrawalRequest.organizationId` has no FK** – Direct prisma schema follow-up; tracks alongside B-024 and B-011. *(new — schema)* +54. **Unauthenticated reserve metrics on `/health/metrics`** – *(moved → B-031)* +55. **Swagger UI exposed without auth** – *(moved → B-033)* +56. **Stellar event listener: broad stream and swallowed errors** – *(moved → B-016)* + +> **Reconciliation policy:** When a follow-up audit pass opens a new canonical ID for items tagged `(new)`, the row is migrated forward and the tagged comment block in this section is updated to point at the new ID. New IDs are expected to land in `B-076+` and should preserve backward-reference to this section so future readers can trace provenance. + +--- + +## 8. Resolution Tracker (Fix Status) + +> **Format:** `ID · title · status · linked PR / commit · owner` +> +> **Forward-looking template.** Every item is currently 🟡 Open; uniformity of status reflects the state of the working backlog. When a fix merges, the row transitions to ✅ Fixed with a PR link. Example anchors below show what a real fixed row looks like. + +| ID | Title | Status | Notes | +|----|-------|--------|-------| +| _(example)_ | _(example anchor for prior documentary PRs — PR #14 for issue #1, PR #22 for issue #12)_ | ✅ Fixed (PR #22 merged) | Documentary PR — not a code fix; historical anchor | +| B-005 | Webhook signature fail-open | 🟡 Open (ship blocker) | Tracked with auth refactor | +| B-006 | Recovery single-factor | 🟡 Open (ship blocker) | Tracked with auth refactor | +| B-001..B-075 (others) | _see Summary Table_ | 🟡 Open | All canonical IDs pending remediation | + +> **Status legend** — 🟢 Trivial/cosmetic · 🟡 Open (tracked) · 🔵 In review · ✅ Fixed (PR linked) +> +> **Reminder when updating:** When an external PR closes an issue, replace `🟡 Open` with `✅ Fixed` and append the merged PR link in the Notes column. Do not rewrite history; the row itself is the audit trail. + +--- + +## 9. Cross-Reference Map + +| Document | Relationship to this file | +|----------|---------------------------| +| [`../../issues/backend.md`](../../issues/backend.md) | **Live triage-ready catalog.** Same IDs and severities; entries are condensed for daily use. | +| [`../../issues/MASTER_INDEX.md`](../../issues/MASTER_INDEX.md) | Master index across backend/frontend/contracts backlogs. | +| [`../../issues/contracts.md`](../../issues/contracts.md) | Smart contracts MVP issues (C-001..C-060). | +| [`../../issues/frontend.md`](../../issues/frontend.md) | Frontend MVP issues (F-001..F-065). | +| [`../API_AND_CONTRACTS_REFERENCE.MD`](../API_AND_CONTRACTS_REFERENCE.MD) | Routes ↔ contracts mapping. | +| [`../PROJECT_STRUCTURE.MD`](../PROJECT_STRUCTURE.MD) | Repo layout (where the backend source lives). | +| [`../../TECHNICAL/ARCHITECTURE.MD`](../../TECHNICAL/ARCHITECTURE.MD) | High-level architecture. | +| [`../../TECHNICAL/API_SPECIFICATION.MD`](../../TECHNICAL/API_SPECIFICATION.MD) | REST API endpoints. | +| [`../../TECHNICAL/DATABASE_SCHEMA.MD`](../../TECHNICAL/DATABASE_SCHEMA.MD) | Database tables and relationships. | +| [`../../OPERATIONS/REGULATORY.MD`](../../OPERATIONS/REGULATORY.MD) | Compliance/regulatory rationale for B-058 (PII encryption at rest), B-059 (GDPR export/delete), B-067 (account enumeration guard). | +| [`../../OPERATIONS/FINTECH_PARTNERSHIPS.MD`](../../OPERATIONS/FINTECH_PARTNERSHIPS.MD) | Multi-provider context for B-045 (also referenced in `correction.md`). | +| [`../../OPERATIONS/LIMITS_AND_TIERS.MD`](../../OPERATIONS/LIMITS_AND_TIERS.MD) | Source of truth for B-001, B-009, B-011, B-046 limit tables. | +| [`../../USER_EXPERIENCE/MERCHANT_INTEGRATION.MD`](../../USER_EXPERIENCE/MERCHANT_INTEGRATION.MD) | bill-pay / merchant context for B-022. | +| [`../../correction.md`](../../correction.md) | Standing list of items curated for fast triage (multi-fintech, basket weight). | +| [`../CONTRACTS_ISSUES.md`](../CONTRACTS_ISSUES.md) | Companion long-form reference for smart contracts. | + +--- + +## 10. Top Remediations (ship-safety order) + +Order these fixes in the MVP launch runbook before deploying mainnet: + +1. **B-005 / B-006** — Webhook fail-closed + recovery second factor (single auth-week PR). +2. **B-007** — Bind all mint / burn / on-ramp recipients to `User.stellarAddress`. +3. **B-001 / B-009** — Correct USD proxy for mint deposits and burn fee math. +4. **B-002 / B-008** — `Decimal` end-to-end on money paths. +5. **B-003 / B-004 / B-075** — RabbitMQ retry caps + DLQ + atomic status transitions. +6. **B-010 / B-011** — Reserve truth reconciliation + org-scoped limits. +7. **B-013 / B-014 / B-015** — Signup Stellar address hygiene + wallet asset choice + dynamic fees. +8. **B-016 / B-028 / B-049** — Listener scope + atomic rate limiter + CORS allowlist. +9. **B-017 / B-020** — KYC machine layer + enterprise bulk transfer. +10. **B-026 / B-053 / B-061 / B-068 / B-073** — Audit durability, idempotency keys, env schema, brute-force guard, transaction state machine. +11. **B-018 / B-021 / B-022 / B-023 / B-024 / B-025** — Segment-API stubs (government, enterprise, bills, investment notifications, yield accounting). +12. **B-031 / B-032 / B-036 / B-037 / B-044 / B-045** — Ops hygiene (deep health, postinstall, jest gate, basket job, multi-fintech). + +--- + +## 11. Maintenance + +- **New issues** — Add to `issues/backend.md` first (canonical triage). Mirror to this file with the next stable `B-###` ID. +- **Closed fixes** — Promote the fix to `✅ Fixed (PR linked)` in Section 8 and link to the merged PR. +- **Legacy `(new)` items in Section 7** — Open a follow-up canonical-ID PR; on merge, update both `issues/backend.md` and this file. +- **Cross-doc references** — Update `issues/MASTER_INDEX.md` summary counts when severities change. + +--- + +## Related Documents + +- [Live backend issue catalog](../../issues/backend.md) +- [Master backlog index](../../issues/MASTER_INDEX.md) +- [Frontend issues](../../issues/frontend.md) +- [Contracts long-form reference](../CONTRACTS_ISSUES.md) +- [Smart contract spec (root copy)](../SMART_CONTRACT_SPEC.md) +- [Project structure map](../PROJECT_STRUCTURE.md) +- [Tech architecture](../../TECHNICAL/ARCHITECTURE.md) +- [API specification](../../TECHNICAL/API_SPECIFICATION.md) +- [Limits & tiers](../../OPERATIONS/LIMITS_AND_TIERS.md) +- [Fintech partnerships](../../OPERATIONS/FINTECH_PARTNERSHIPS.md) --- -## Critical - -1. **API key validation broken** – src/middleware/auth.ts: `validateApiKey` uses `keyHash: await hashApiKey(apiKey)` for lookup. `hashApiKey` calls `bcrypt.hash()`, which produces a different hash each time (random salt). Stored hashes will never match. Use `bcrypt.compare(plaintextApiKey, storedKeyHash)` instead of hashing the input for lookup. -2. **Wrong import in usdcConvertAndMintJob** – src/jobs/usdcConvertAndMintJob.ts: Imports `db` from `../config/database`, but that module exports `prisma`. The code uses `prisma`, which is never imported, causing a `ReferenceError` at runtime. -3. **IDOR / auth bypass in savings controller** – src/controllers/savingsController.ts: `user` is taken from `req.body` or `req.query` without checking it against the authenticated user. Any authenticated user can operate on another user's savings by supplying a different `user` ID. -4. **Env validation too late** – src/config/env.ts: `requiredEnvVars` is checked after `config` is built. If `DATABASE_URL` is missing, the app may still start and fail later. Validation should run before any use of `config`. - -## High - -5. **Infinite retries for failed webhooks** – src/services/webhook/webhookService.ts: When `status === 'failed'`, `deliverWebhook` still attempts delivery and returns `false`, so the consumer nacks and requeues indefinitely. Add early return for failed status. -6. **Organization users never notified for investment withdrawal** – src/jobs/investmentWithdrawalJob.ts: `publishInvestmentWithdrawalReady` only fires when `r.userId` is set. For organization requests (`r.organizationId` set, `r.userId` null), no notification is sent. -7. **Burn limits bypass when `audience` is unset** – src/controllers/burnController.ts: `checkWithdrawalLimits` and `isCurrencyWithdrawalPaused` run only when `req.audience` is set. `/burn/acbu` via `burnRoutes` does not set `audience`, so limits and circuit breakers are skipped. -8. **Mint limits bypass when `audience` is unset** – src/controllers/mintController.ts: `isMintingPaused` and `checkDepositLimits` run only when `req.audience` is set. `/mint/usdc` and `/mint/deposit` via `mintRoutes` do not set `audience`, so limits are bypassed. -9. **Fee thresholds likely wrong** – src/services/feePolicy/feePolicyService.ts: `getBurnFeeBps` uses `pctOfTarget < 15` and `pctOfTarget > 21`. With `pctOfTarget = (actualWeight / targetWeight) * 100`, these look like typos (should be 85/115). Logic is unlikely to behave as intended. -10. **Decimal vs string for `acbuAmount` in transfer** – src/services/transfer/transferService.ts: `acbuAmount` is passed as a string to `prisma.transaction.create`. Prisma expects `Decimal` for that field; this can cause type or precision issues. -11. **No dead-letter queues** – src/config/rabbitmq.ts: Queues are declared without `deadLetterExchange` or `deadLetterRoutingKey`. Messages that repeatedly fail are requeued forever instead of being moved to a DLQ. -12. **No max retry limit for webhook consumer** – src/jobs/webhookConsumer.ts: Failed webhooks are nacked with requeue indefinitely. There is no per-message retry cap. - -## Medium - -13. **Wallet activation uses XLM, not Pi** – src/services/wallet/walletActivationService.ts: Sends XLM to activate Stellar accounts; comment says "using pi instead of xlm" is desired. Switch to Pi when the Pi bridge/chain is in use. -14. **Remove placeholder Stellar address in auth** – src/services/auth/authService.ts: Uses `getPlaceholderStellarAddress()` on signup to satisfy schema before the real wallet exists. Replace with a proper flow. -15. **Transfer service: verify alias-based flow** – Transfer supports sending by username/phone (via recipientResolver); confirm the current resolve-to-Stellar flow is correct, secure, and documented. -16. **Contract client and Stellar fees hardcoded** – src/services/stellar/contractClient.ts defaults fee to `'100'`; walletActivationService.ts and transferService.ts also use hardcoded `'100'`. Make fees configurable or network-derived. -17. **Multiple fintech providers per nation** – Only Flutterwave is wired in webhookRoutes; add support for multiple providers per country (e.g. Nigeria: Paystack and Flutterwave) to avoid single point of failure. -18. **KYC extraction placeholder** – src/services/kyc/machineLayer.ts: Uses a placeholder for "real impl would call Vision API and redact"; replace with actual implementation. -19. **Basket weight script missing** – Create a backend/tooling script or job that computes and reports current basket weights based on market conditions and factors considered. -20. **Balance endpoint for frontend missing** – Frontend shows balance as placeholder "—" everywhere; add or expose GET /users/me/balance so the UI can display real balances. -21. **No dependency health checks** – /health/metrics does not verify PostgreSQL, MongoDB, or RabbitMQ. A "healthy" response can be returned even when core dependencies are down. -22. **Race condition in API key rate limiting** – src/middleware/rateLimiter.ts: The get-then-set flow for rate limit counters is not atomic. Concurrent requests can both pass the limit before either updates the cache. -23. **ReDoS risk in `deletePattern`** – src/utils/cache.ts: `new RegExp(pattern)` with user-controlled or unsanitized input can lead to ReDoS. Patterns should be validated or escaped. -24. **Webhook verification skipped when secret missing** – src/controllers/webhookController.ts: If `FLUTTERWAVE_WEBHOOK_SECRET` is unset, `verifyFlutterwaveSignature` calls `next()` and skips verification, allowing forged webhooks. -25. **Placeholder Stellar address format invalid** – src/services/auth/authService.ts: `getPlaceholderStellarAddress()` returns `'P' + ...` (56 chars). Stellar addresses start with `G`. This may violate schema or downstream validation. -26. **ACBU supply from DB, not chain** – src/services/reserve/ReserveTracker.ts: `getTotalAcbuSupply` uses transaction aggregates instead of on-chain supply. This can diverge from the real supply if there are off-chain mints/burns. -27. **Org-scoped limits may not apply** – src/services/limits/limitsService.ts: For org-level API keys (`userId` null), transactions created with `userId: null` have no user relation, so they are excluded from limit aggregates. -28. **USDC to XLM conversion is a no-op** – src/jobs/usdcConvertAndMintJob.ts: `convertUsdcToXlm` is empty. USDC is never converted; the job still mints ACBU as if conversion succeeded. -29. **Hardcoded XLM rate** – src/jobs/xlmToAcbuJob.ts: `XLM_USD_RATE` defaults to `0.2` from env. A wrong or stale rate can cause incorrect ACBU mint amounts. -30. **Deposit limits use wrong USD equivalent** – src/controllers/mintController.ts: `amountUsdPlaceholder = amountNum` treats local currency amount as USD for limit checks. Limits should use a proper USD conversion. -31. **Incomplete treasury aggregation** – src/controllers/governmentController.ts: TODO: aggregate from transactions for org/user and reserve exposure. `byCurrency` is always `[]`. -32. **Audit failures are silent** – src/services/audit/auditService.ts: Audit write failures are only logged. There is no retry, alerting, or fallback, so audit data can be lost without visibility. - -## Low - -33. **`any` cast for permissions** – src/middleware/auth.ts: `permissions: permissions as any` bypasses type safety. Use a proper type. -34. **`any` usage in segmentGuard** – src/middleware/segmentGuard.ts: `(req as any).userTier` and `tier as any` weaken type safety. -35. **`any` usage in Stellar client** – src/services/stellar/client.ts: `submitTransaction(transaction: any)` and `(b: any)` in balance lookups. -36. **`any` cast in burning service** – src/services/contracts/acbuBurning.service.ts: `localAmounts as any[]` bypasses type checking. -37. **No pagination on transfers** – src/controllers/transferController.ts: `getTransfers` uses `take: 50` with no `skip` or cursor. No way to page through older transfers. -38. **No pagination on investment withdrawals** – src/controllers/investmentController.ts: `getInvestmentWithdrawRequests` uses `take: 50` with no pagination parameters. -39. **`limit` query param not validated** – src/controllers/governmentController.ts: `Number(req.query.limit)` can be `NaN`; `Math.max(1, NaN)` is `NaN`. -40. **No input validation in savings controller** – src/controllers/savingsController.ts: `amount`, `term_seconds`, and `user` are not validated with Zod or similar. Invalid values can reach the service layer. -41. **Missing composite index** – prisma/schema.prisma: `OnRampSwap` is often queried by `(status, createdAt)`. A composite index would help those queries. -42. **Webhook JSON parse failure returns empty body** – src/index.ts: If `raw.toString()` is invalid JSON, `body` is set to `{}`. The webhook handler may run with incomplete data instead of returning 400. -43. **Stack traces in error logs** – src/errorHandler.ts: `logger.error('Unexpected error', { error: err, ... })` can log full error objects. Ensure logs are not exposed to clients and that PII is not included. - -## Trivial - -44. **`(prisma as any).onRampSwap` casts** – src/jobs/usdcConvertAndMintJob.ts, xlmToAcbuJob.ts, mintController.ts, onrampController.ts: Prisma client is cast to `any` to access `onRampSwap`. Run `npx prisma generate` and fix the schema/client so `onRampSwap` is properly typed. -45. **Hardcoded limit values** – src/config/limits.ts: Deposit/withdrawal limits are hardcoded. Consider loading from env or config for easier tuning. -46. **Fallback email placeholder** – src/services/notification/notificationService.ts: `noreply@acbu.example.com` is a placeholder and may not be valid in production. -47. **Yield accounting stub** – src/services/investment/yieldAccountingService.ts: Placeholder only; yield accounting is not implemented. -48. **No automated tests** – No `*.test.ts` or `*.spec.ts` files found. Critical paths (auth, transfers, limits, webhooks) lack automated tests. -49. **Client-controlled mint recipient** – src/controllers/mintController.ts, onrampController.ts: Mint/on-ramp flows take a body-supplied Stellar address (`wallet_address` / `stellar_address`) and pass it to `mintFromUsdcInternal` as the chain recipient with no check that it matches the authenticated user's `User.stellarAddress`. A caller could direct minted ACBU to any address. -50. **Rate limiting fails open when MongoDB cache is down** – src/middleware/rateLimiter.ts, src/utils/cache.ts: `apiKeyRateLimiter` relies on Mongo-backed `cacheService`. On `get`/`set` errors the cache returns `null` or swallows failures, so under Mongo outages per-API-key limits do not accumulate, weakening abuse protection. -51. **Recovery unlock is single-factor** – src/services/recovery/recoveryService.ts: `POST /recovery/unlock` returns a new API key after only identifier + passcode — no OTP, email link, or second step. Weak or stolen passcodes enable account takeover. -52. **`requireMinTier` middleware is never used** – src/middleware/segmentGuard.ts: `requireMinTier` is defined but no route imports or applies it. The `User.tier` field is therefore not enforced at the middleware layer. -53. **`InvestmentWithdrawalRequest.organizationId` has no FK** – prisma/schema.prisma: `organizationId` is optional `String?` with no `Organization` relation or `@relation`. The DB cannot enforce that it references a real organization, enabling orphan rows. -54. **Unauthenticated reserve metrics on `/health/metrics`** – src/routes/index.ts: `GET /health/metrics` is not behind `validateApiKey`. It returns reserve ratio, overcollateralization ratio, and reserve health — operationally sensitive data — without authentication. -55. **Swagger UI exposed without auth** – src/index.ts: `app.use('/api-docs', swaggerUi.serve, …)` is mounted without API-key middleware, so the full OpenAPI surface is available for unauthenticated reconnaissance. -56. **Stellar event listener: broad stream and swallowed errors** – src/services/stellar/eventListener.ts: Listener walks global Horizon `effects()` (not scoped to known contract IDs), which is heavy and error-prone. Per-handler failures are logged and swallowed, so contract-dependent jobs can miss state with no retry or dead-letter. +_Last consolidated: June 2026. Source content merged from legacy `PROJECT/issues/BACKEND_ISSUES.md` list (56 items) and canonical [`issues/backend.md`](../../issues/backend.md) (75 items). Severity buckets and IDs fully aligned with canonical catalog; legacy 56-item list preserved as Section 7 with `(moved)` and `(new)` tags for traceability. New audit findings captured under `(new)` should be promoted to canonical IDs (`B-076+`) in a follow-up PR._ From 4b6ff1c7671a59388201202a49b4cf78a26c7bb6 Mon Sep 17 00:00:00 2001 From: Adiz4415 Date: Sat, 20 Jun 2026 12:47:15 +0000 Subject: [PATCH 03/11] docs(index): add CHANGELOG + per-item Top-20 tracker pointers - Catalog sources & deduping section renames the prior Deduping section and explicitly elevates PROJECT/issues/CONTRACTS_ISSUES.md (PR #22) and PROJECT/issues/BACKEND_ISSUES.md (PR #23) to durable long-form references; FRONTEND_ISSUES.md remains legacy pending follow-up PR. - Top 20 list gains per-item deep links to the Resolution Tracker (Section 8) of each consolidated catalog and uniformly bolds IDs. - New CHANGELOG section appended in strict reverse-chronological order (this PR refresh first, then PR #23 backend, then PR #22 contracts, then future frontend consolidation). --- issues/MASTER_INDEX.md | 68 ++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/issues/MASTER_INDEX.md b/issues/MASTER_INDEX.md index fc844d8..3291ada 100644 --- a/issues/MASTER_INDEX.md +++ b/issues/MASTER_INDEX.md @@ -14,31 +14,53 @@ This folder consolidates **~200** MVP flaws and improvements across: 2. Create tickets in your tracker; keep the **Evidence** path as the source anchor. 3. When an item is fixed, prefer **linking the PR** in your tracker (avoid editing this backlog as a changelog). -## Deduping against older docs +## Catalog sources & deduping -- Legacy consolidated lists: [../PROJECT/issues/BACKEND_ISSUES.md](../PROJECT/issues/BACKEND_ISSUES.md), [../PROJECT/issues/FRONTEND_ISSUES.md](../PROJECT/issues/FRONTEND_ISSUES.md), [../PROJECT/issues/CONTRACTS_ISSUES.md](../PROJECT/issues/CONTRACTS_ISSUES.md). -- Repo-root `ISSUES.md` / `acbu-smart-contract/ISSUES.md` may also exist; treat them as **historical** unless actively maintained. +- **Live triage-ready catalogs in this folder (canonical working backlog):** + - [backend.md](./backend.md) — 75 items (B-001..B-075) + - [frontend.md](./frontend.md) — 65 items (F-001..F-065) + - [contracts.md](./contracts.md) — 60 items (C-001..C-060) +- **Durable long-form references in `PROJECT/issues/`** (consolidated mirrors, see CHANGELOG): + - [../PROJECT/issues/CONTRACTS_ISSUES.md](../PROJECT/issues/CONTRACTS_ISSUES.md) — consolidated into the canonical format in [PR #22](https://github.com/Pi-Defi-world/ACBU-DOCUMENTATION/pull/22); single source of truth, with Resolution Tracker (Section 8), Top Remediations ship-safety list, and Cross-Reference Map. + - [../PROJECT/issues/BACKEND_ISSUES.md](../PROJECT/issues/BACKEND_ISSUES.md) — consolidated into the canonical format in [PR #23](https://github.com/Pi-Defi-world/ACBU-DOCUMENTATION/pull/23). + - [../PROJECT/issues/FRONTEND_ISSUES.md](../PROJECT/issues/FRONTEND_ISSUES.md) — legacy list; same pattern pending a follow-up PR. +- **Truly historical (read-only):** Repo-root `ISSUES.md` / `acbu-smart-contract/ISSUES.md` may also exist; treat as historical unless actively maintained. ## Top 20 (ship-safety order) -1. C-001 Escrow `release` missing auth (contracts) -2. C-005 Savings vault missing `require_auth` (contracts) -3. C-006 Lending pool missing `require_auth` (contracts) -4. C-002 `mint_from_fiat` unrestricted (contracts) -5. F-001 Next.js `ignoreBuildErrors` (frontend build safety) -6. F-002 API key in `sessionStorage` (frontend) -7. F-003 Passcode stored in `sessionStorage` for wallet decrypt path (frontend) -8. F-004 Wallet secret 'encryption' is reversible (frontend) -9. F-005 Plaintext wallet storage path exists (frontend) -10. B-005 Webhook signature verification fail-open risk (backend) -11. B-006 Recovery unlock single-factor risk (backend) -12. B-003 USDC job infinite requeue risk (backend) -13. B-001 Basket deposit USD limit proxy wrong (backend) -14. B-002 Floating `Number()` on money paths (backend) -15. C-004 `verify_reserves` wrong supply source (contracts) -16. C-003 Escrow ID collision (contracts) -17. B-010 ReserveTracker DB vs chain supply drift (backend) -18. B-009 Burn fee policy threshold correctness (backend) -19. F-015 Savings deposit not wired (frontend) -20. B-022 Bills catalog/pay not implemented (backend) + F-020 Bills payment UI console-only (frontend) +_Per-item fix status is tracked in the [Resolution Tracker](../PROJECT/issues/CONTRACTS_ISSUES.md#resolution-tracker-fix-status) added in [PR #22](https://github.com/Pi-Defi-world/ACBU-DOCUMENTATION/pull/22) (plus the analogous [backend Resolution Tracker](../PROJECT/issues/BACKEND_ISSUES.md#resolution-tracker-fix-status) in [PR #23](https://github.com/Pi-Defi-world/ACBU-DOCUMENTATION/pull/23)). The Top 20 below is the ship-safety triage ordering; the corresponding canonical IDs in each contract/PR's Resolution Tracker are the canonical record of open/fixed status._ + +1. **C-001** Escrow `release` missing auth (contracts) — [tracker](../PROJECT/issues/CONTRACTS_ISSUES.md#resolution-tracker-fix-status) +2. **C-005** Savings vault missing `require_auth` (contracts) — [tracker](../PROJECT/issues/CONTRACTS_ISSUES.md#resolution-tracker-fix-status) +3. **C-006** Lending pool missing `require_auth` (contracts) — [tracker](../PROJECT/issues/CONTRACTS_ISSUES.md#resolution-tracker-fix-status) +4. **C-002** `mint_from_fiat` unrestricted (contracts) — [tracker](../PROJECT/issues/CONTRACTS_ISSUES.md#resolution-tracker-fix-status) +5. **F-001** Next.js `ignoreBuildErrors` (frontend build safety) +6. **F-002** API key in `sessionStorage` (frontend) +7. **F-003** Passcode stored in `sessionStorage` for wallet decrypt path (frontend) +8. **F-004** Wallet secret 'encryption' is reversible (frontend) +9. **F-005** Plaintext wallet storage path exists (frontend) +10. **B-005** Webhook signature verification fail-open risk (backend) — [tracker](../PROJECT/issues/BACKEND_ISSUES.md#resolution-tracker-fix-status) +11. **B-006** Recovery unlock single-factor risk (backend) — [tracker](../PROJECT/issues/BACKEND_ISSUES.md#resolution-tracker-fix-status) +12. **B-003** USDC job infinite requeue risk (backend) — [tracker](../PROJECT/issues/BACKEND_ISSUES.md#resolution-tracker-fix-status) +13. **B-001** Basket deposit USD limit proxy wrong (backend) — [tracker](../PROJECT/issues/BACKEND_ISSUES.md#resolution-tracker-fix-status) +14. **B-002** Floating `Number()` on money paths (backend) — [tracker](../PROJECT/issues/BACKEND_ISSUES.md#resolution-tracker-fix-status) +15. **C-004** `verify_reserves` wrong source of truth (contracts) — [tracker](../PROJECT/issues/CONTRACTS_ISSUES.md#resolution-tracker-fix-status) +16. **C-003** Escrow ID collision (contracts) — [tracker](../PROJECT/issues/CONTRACTS_ISSUES.md#resolution-tracker-fix-status) +17. **B-010** ReserveTracker DB vs chain supply drift (backend) — [tracker](../PROJECT/issues/BACKEND_ISSUES.md#resolution-tracker-fix-status) +18. **B-009** Burn fee policy threshold correctness (backend) — [tracker](../PROJECT/issues/BACKEND_ISSUES.md#resolution-tracker-fix-status) +19. **F-015** Savings deposit not wired (frontend) +20. **B-022** Bills catalog/pay not implemented (backend) & **F-020** Bills payment UI console-only (frontend) + +--- + +## CHANGELOG + +This is the master index's own changelog. Catalog-level changes that affect this index are recorded here in **strict reverse-chronological order** (newest first); per-item fix tickets claim their own PR history via the linked Resolution Trackers. + +- **2026-06 (PR TBD) — MASTER_INDEX.md refresh.** Replaced the older `Deduping against older docs` section with a `Catalog sources & deduping` section that distinguishes three states — **canonical triage-ready** (this folder), **durable long-form** (`PROJECT/issues/`, consolidated), and **truly historical** (read-only). Forward links to [PR #22](https://github.com/Pi-Defi-world/ACBU-DOCUMENTATION/pull/22) (contracts consolidation — what formally elevates `PROJECT/issues/CONTRACTS_ISSUES.md` to single-source-of-truth) and [PR #23](https://github.com/Pi-Defi-world/ACBU-DOCUMENTATION/pull/23) (backend consolidation) are now provided. The Top 20 list below anchors per-item trackers to the **Resolution Tracker (Section 8) of each consolidated catalog**, so reviewers can confirm open/fixed status at a glance. `PROJECT/issues/FRONTEND_ISSUES.md` is the only remaining legacy list pending its follow-up PR. +- **2026-06 — Backend catalog consolidation ([PR #23](https://github.com/Pi-Defi-world/ACBU-DOCUMENTATION/pull/23)).** `PROJECT/issues/BACKEND_ISSUES.md` consolidated into the canonical severity/area/evidence/impact/fix/acceptance format with all 75 entries (B-001..B-075); severity distribution 2 Critical / 21 High / 38 Medium / 14 Low. Added an equivalent [Resolution Tracker](../PROJECT/issues/BACKEND_ISSUES.md#resolution-tracker-fix-status) (Section 8), Top Remediations ship-safety list, Cross-Reference Map, and legacy 56-item cross-reference. The legacy `(new)` items in Section 7 propose follow-up canonical IDs (`B-076+`) once a separate PR promotes them. +- **2026-06 — Contracts catalog consolidation ([PR #22](https://github.com/Pi-Defi-world/ACBU-DOCUMENTATION/pull/22)).** `PROJECT/issues/CONTRACTS_ISSUES.md` is now the **single source of truth** for smart-contract issues. Coverage expanded from a 34-item flat list to all 60 canonical entries (C-001..C-060) with stable IDs in the severity/area/evidence/impact/fix/acceptance format used by `issues/contracts.md`. Severity distribution: 6 Critical / 21 High / 24 Medium / 9 Low. + - New structural sections in `PROJECT/issues/CONTRACTS_ISSUES.md`: Summary Table, Severity Counts, **Resolution Tracker (Section 8)**, Top Remediations (ship-safety order), Cross-Reference Map, legacy 34-item cross-reference, Maintenance notes. + - The Top 20 list below references the [Resolution Tracker](../PROJECT/issues/CONTRACTS_ISSUES.md#resolution-tracker-fix-status) so reviewers can confirm open/fixed status at a glance; the same pattern is duplicated to the consolidated backend catalog (above) and (planned) frontend catalog. +- **_(Future) Frontend catalog consolidation._** `PROJECT/issues/FRONTEND_ISSUES.md` is currently still a legacy flat list. The same consolidation pattern (canonical format + Summary Table + Severity Counts + Resolution Tracker + Top Remediations + Cross-Reference Map) is planned as a follow-up PR; once merged, this CHANGELOG entry will be updated with the PR number and frontend tracker pointers will be added to the Top 20 list above. From 4835439e272d56914dacf7fc530678806682f203 Mon Sep 17 00:00:00 2001 From: Adiz4415 Date: Sat, 20 Jun 2026 12:52:51 +0000 Subject: [PATCH 04/11] docs(frontend): consolidate FRONTEND_ISSUES.md catalog --- PROJECT/issues/FRONTEND_ISSUES.md | 839 ++++++++++++++++++++++++++---- 1 file changed, 724 insertions(+), 115 deletions(-) diff --git a/PROJECT/issues/FRONTEND_ISSUES.md b/PROJECT/issues/FRONTEND_ISSUES.md index f264ad7..d554c79 100644 --- a/PROJECT/issues/FRONTEND_ISSUES.md +++ b/PROJECT/issues/FRONTEND_ISSUES.md @@ -1,124 +1,733 @@ -# Frontend – Known Issues +# Frontend — Known Issues -Issues found in the Next.js app and API usage. Add new items below as numbered list entries. +This document is the **single, durable long-form reference** for known issues in the ACBU frontend (`acbu-frontend`, Next.js 14 + React + Stellar SDK), covering all routes under `app/(app)/**` (segments), the auth surface (`app/(public)/auth/**`), settings, wallet, savings, lending, currency, bills, and the lib/api + lib/stellar + lib/wallet-storage + lib/auth surface. + +> **How to use** +> +> - Each issue is structured as: **severity · area · evidence · impact · fix direction · acceptance check**. +> - Items are ordered by severity (Critical → Low), then by ID for stable cross-referencing. +> - Provenance: this file consolidates the legacy 77-item annotated list previously at `PROJECT/issues/FRONTEND_ISSUES.md` with the canonical 65-item triage-ready list at `issues/frontend.md`. The canonical list at `issues/frontend.md` remains the **live working backlog**; this file is the durable version-of-record. +> - Legacy items whose content maps to a canonical `F-###` ID are tagged **(moved)**; legacy items that go beyond the canonical list (newer findings) are tagged **(new)** and retained verbatim because they pre-date the canonical rewrite. +> - When an item is fixed, the corresponding entry is removed from the working lists (`issues/frontend.md`) and the resolution row flips to ✅ Fixed in Section 8 with a merged-PR link. +> - **Severity legend:** 🔴 Critical · 🟠 High · 🟡 Medium · 🟢 Low + +--- + +## 1. Summary Table + +| ID | Severity | Area | Title (canonical) | +|----|----------|------|---------| +| F-001 | 🔴 Critical | frontend/build | Next.js production build ignores TypeScript errors | +| F-002 | 🔴 Critical | frontend/auth | API key stored in sessionStorage | +| F-003 | 🔴 Critical | frontend/wallet | Passcode stored in sessionStorage for wallet decrypt path | +| F-004 | 🔴 Critical | frontend/wallet | Wallet secret "encryption" is base64 obfuscation | +| F-005 | 🔴 Critical | frontend/wallet | Plaintext wallet secret storage path exists | +| F-006 | 🟠 High | frontend/auth | 2FA challenge token in URL query | +| F-007 | 🟡 Medium | frontend/api | Dual Authorization + x-api-key headers | +| F-008 | 🟢 Low | frontend/api | Client-side global fetch timeout without abort sharing | +| F-009 | 🟡 Medium | frontend/security | CSRF cookie read without backend pairing guarantee | +| F-010 | 🟠 High | frontend/deps | Duplicate Stellar SDK dependencies | +| F-011 | 🟢 Low | frontend/devx | Package name still `my-v0-project` | +| F-012 | 🟡 Medium | frontend/qa | No `test` / `typecheck` scripts in frontend | +| F-013 | 🟡 Medium | frontend/devx | Both `package-lock.json` and `pnpm-lock.yaml` | +| F-014 | 🟠 High | frontend/ux-money | Send success dialog clears amount before dialog | +| F-015 | 🟠 High | frontend/feature | Savings deposit handler is console-only | +| F-016 | 🟡 Medium | frontend/feature | Savings New Goal button inert | +| F-017 | 🟡 Medium | frontend/feature | SME CTAs inert | +| F-018 | 🟠 High | frontend/feature | Lending application console-only | +| F-019 | 🟠 High | frontend/feature | Currency page simulates operations | +| F-020 | 🟠 High | frontend/feature | Bills payment console-only | +| F-021 | 🟠 High | frontend/wallet | Wallet confirm disabled / incomplete | +| F-022 | 🟠 High | frontend/settings | Security settings placeholder | +| F-023 | 🟠 High | frontend/mint | Mint page burn tab fake success | +| F-024 | 🟡 Medium | frontend/copy | AFK vs ACBU naming drift | +| F-025 | 🟠 High | frontend/data | Balances shown as em dash placeholders | +| F-026 | 🟡 Medium | frontend/data | Savings page mixes mock cards with API data | +| F-027 | 🟠 High | frontend/ux-risk | Savings withdraw recipient editable | +| F-028 | 🟡 Medium | frontend/mint | Hardcoded fees on mint UI | +| F-029 | 🟡 Medium | frontend/me | Me page KYC badge static | +| F-030 | 🟡 Medium | frontend/me | Me page hardcoded stats | +| F-031 | 🟢 Low | frontend/business | Business page hardcoded stats | +| F-032 | 🟡 Medium | frontend/nav | International/Gateway stubs | +| F-033 | 🟢 Low | frontend/support | Help page too thin | +| F-034 | 🟢 Low | frontend/auth | Sign-in label says Username only | +| F-035 | 🟢 Low | frontend/auth | Signup success query param ignored | +| F-036 | 🟡 Medium | frontend/transfers | Send note omitted from confirm + API | +| F-037 | 🟡 Medium | frontend/quality | Inconsistent API error UX across pages | +| F-038 | 🟡 Medium | frontend/reliability | Silent catch on send loads | +| F-039 | 🟡 Medium | frontend/reliability | No React error boundary | +| F-040 | 🟡 Medium | frontend/react | useEffect dependency hazards (send/contacts/guardians/kyc) | +| F-041 | 🟢 Low | frontend/savings | Savings deposit URI length filter too strict | +| F-042 | 🟢 Low | frontend/types | `as any` tabs in bills/currency | +| F-043 | 🟢 Low | frontend/hygiene | console.log in money handlers | +| F-044 | 🟢 Low | frontend/react | Unstable list keys (rates/mint) | +| F-045 | 🟢 Low | frontend/product | No i18n / localization | +| F-046 | 🟡 Medium | frontend/a11y | Accessibility: labels without htmlFor | +| F-047 | 🟡 Medium | frontend/a11y | Mobile nav icon-only links lack aria-label | +| F-048 | 🟢 Low | frontend/theme | Dark mode badge colors hardcoded light palette | +| F-049 | 🟢 Low | frontend/ux | Back navigation pattern inconsistent | +| F-050 | 🟡 Medium | frontend/forms | Burn form lacks strong validation | +| F-051 | 🟠 High | frontend/auth | Signup passcode minimum too weak | +| F-052 | 🟢 Low | frontend/forms | Send amount missing min attribute | +| F-053 | 🟢 Low | frontend/nav | Activity links wrong route target | +| F-054 | 🟢 Low | frontend/nav | Me page links 2FA to auth flow not settings | +| F-055 | 🟡 Medium | frontend/html | Nested interactive elements (Link in Button) | +| F-056 | 🟢 Low | frontend/formatting | Amount formatting inconsistent | +| F-057 | 🟢 Low | frontend/education | Reserves page lacks unit explanations | +| F-058 | 🟢 Low | frontend/formatting | Rates page number formatting | +| F-059 | 🟢 Low | frontend/formatting | Burn page currency display locale | +| F-060 | 🟢 Low | frontend/perf | Performance: send page callbacks not memoized | +| F-061 | 🟢 Low | frontend/compat | Clipboard API failure on HTTP | +| F-062 | 🟡 Medium | frontend/stellar | Stellar burning client uses `as any` on send response | +| F-063 | 🟠 High | frontend/config | Environment base URL misconfiguration footgun | +| F-064 | 🟡 Medium | frontend/security | No Content-Security-Policy for Next app | +| F-065 | 🟢 Low | frontend/security | No Subresource Integrity for third-party scripts (if any) | + +**Totals:** 5 Critical · 14 High · 23 Medium · 23 Low · **65 total catalog items** (all IDs `F-001` through `F-065`, fully aligned with `issues/frontend.md`). + +--- + +## 2. Severity Counts + +| Severity | Count | +|----------|-------| +| 🔴 Critical | **5** (F-001–F-005) | +| 🟠 High | **14** (F-006, F-010, F-014, F-015, F-018–F-023, F-025, F-027, F-051, F-063) | +| 🟡 Medium | **23** (F-007, F-009, F-012, F-013, F-016, F-017, F-024, F-026, F-028–F-030, F-032, F-036–F-040, F-046, F-047, F-050, F-055, F-062, F-064) | +| 🟢 Low | **23** (F-008, F-011, F-031, F-033–F-035, F-041–F-045, F-048, F-049, F-052–F-054, F-056–F-061, F-065) | +| **Total** | **65** | + +--- + +## 3. Critical Issues (🔴) — Ship Blockers + +### F-001 — Next.js production build ignores TypeScript errors +- **Area:** frontend/build +- **Evidence:** `acbu-frontend/next.config.mjs` (`typescript.ignoreBuildErrors`) +- **Impact:** Type errors ship to prod → runtime crashes and security holes. +- **Fix direction:** Set `ignoreBuildErrors: false`; fix surfaced errors; add `typecheck` CI. +- **Acceptance check:** `next build` fails on any TS error in CI. + +### F-002 — API key stored in sessionStorage +- **Area:** frontend/auth +- **Evidence:** `acbu-frontend/contexts/auth-context.tsx` +- **Impact:** XSS exfiltration steals long-lived API keys. +- **Fix direction:** Move to httpOnly cookie session or short-lived JWT + refresh; CSP strict. +- **Acceptance check:** No secrets in `sessionStorage` in prod build. + +### F-003 — Passcode stored in sessionStorage for wallet decrypt path +- **Area:** frontend/wallet +- **Evidence:** `acbu-frontend/lib/wallet-storage.ts` (`KEY_STORE_PASSPHRASE` via sessionStorage in `getWalletSecretAnyLocal`) +- **Impact:** Passcode + encrypted secret becomes trivially stealable together under XSS. +- **Fix direction:** Use WebCrypto + non-extractable keys; never store passcode in session storage. +- **Acceptance check:** Security review: passcode only in memory during operation. + +### F-004 — Wallet secret "encryption" is base64 obfuscation +- **Area:** frontend/wallet +- **Evidence:** `acbu-frontend/lib/wallet-storage.ts` (`encryptSecret`) +- **Impact:** Stellar secret key is not confidential at rest. +- **Fix direction:** Implement AES-GCM with PBKDF2/Argon2 derived keys; hardware wallet path for prod. +- **Acceptance check:** Pen test cannot recover secret from IndexedDB dump without passcode. + +### F-005 — Plaintext wallet secret storage path exists +- **Area:** frontend/wallet +- **Evidence:** `acbu-frontend/lib/wallet-storage.ts` (`storeWalletSecretLocalPlaintext`) +- **Impact:** Dev helper enables catastrophic prod misconfiguration. +- **Fix direction:** Strip from prod bundles behind `NODE_ENV === "development"` only; runtime assert. +- **Acceptance check:** Production build throws if plaintext store called. + +--- + +## 4. High Severity Issues (🟠) + +### F-006 — 2FA challenge token in URL query +- **Area:** frontend/auth +- **Evidence:** `acbu-frontend/app/auth/2fa/page.tsx` +- **Impact:** Token leaks via Referer headers, browser history, server logs. +- **Fix direction:** POST body one-time token or encrypted state cookie. +- **Acceptance check:** Token never appears in URL bar or server access logs. + +### F-010 — Duplicate Stellar SDK dependencies +- **Area:** frontend/deps +- **Evidence:** `acbu-frontend/package.json` (`@stellar/stellar-sdk` + `stellar-sdk`) +- **Impact:** Two major versions inflate bundle and cause subtle type/runtime mismatches. +- **Fix direction:** Remove legacy `stellar-sdk`; migrate imports. +- **Acceptance check:** Only one stellar sdk in lockfile. + +### F-014 — Send success dialog clears amount before dialog +- **Area:** frontend/ux-money +- **Evidence:** `acbu-frontend/app/(app)/send/page.tsx` +- **Impact:** Users cannot confirm how much was sent. +- **Fix direction:** Keep amount in state until dialog dismissed. +- **Acceptance check:** Visual regression or unit test asserts non-empty amount. + +### F-015 — Savings deposit handler is console-only +- **Area:** frontend/feature +- **Evidence:** `acbu-frontend/app/(app)/savings/page.tsx` +- **Impact:** Core savings MVP non-functional. +- **Fix direction:** Wire to `POST /savings/...` endpoints; handle errors. +- **Acceptance check:** Deposit creates pending/completed UI state from API. + +### F-018 — Lending application console-only +- **Area:** frontend/feature +- **Evidence:** `acbu-frontend/app/(app)/lending/page.tsx` +- **Impact:** No loan intake for MVP. +- **Fix direction:** Create lending application API + form. +- **Acceptance check:** Submitted application visible in admin/backoffice stub. + +### F-019 — Currency page simulates operations +- **Area:** frontend/feature +- **Evidence:** `acbu-frontend/app/(app)/currency/page.tsx` +- **Impact:** Users think trades executed. +- **Fix direction:** Replace `setTimeout` with real API calls + toasts. +- **Acceptance check:** Network tab shows POST to backend on confirm. + +### F-020 — Bills payment console-only +- **Area:** frontend/feature +- **Evidence:** `acbu-frontend/app/(app)/bills/page.tsx` +- **Impact:** Bill pay is fake. +- **Fix direction:** Integrate bills endpoints when ready; else gate feature flag off. +- **Acceptance check:** Feature flag off shows honest copy. + +### F-021 — Wallet confirm disabled / incomplete +- **Area:** frontend/wallet +- **Evidence:** `acbu-frontend/app/me/settings/wallet/page.tsx` +- **Impact:** Users cannot finish wallet setup. +- **Fix direction:** Complete confirm flow + backend sync. +- **Acceptance check:** E2E completes wallet activation. + +### F-022 — Security settings placeholder +- **Area:** frontend/settings +- **Evidence:** `acbu-frontend/app/me/settings/security/page.tsx` +- **Impact:** 2FA management missing for financial app. +- **Fix direction:** Wire rotate device, sessions list, API keys. +- **Acceptance check:** User can disable compromised sessions. + +### F-023 — Mint page burn tab fake success +- **Area:** frontend/mint +- **Evidence:** `acbu-frontend/app/(app)/mint/page.tsx` +- **Impact:** False confirmation risk. +- **Fix direction:** Call burn API or deep-link with params. +- **Acceptance check:** Burn tab hits network or routes to `/burn` with prefilled state. + +### F-025 — Balances shown as em dash placeholders +- **Area:** frontend/data +- **Evidence:** Home/mint/send/savings pages +- **Impact:** Users cannot trust balances for decisions. +- **Fix direction:** Use `/users/me/balance` (or equivalent) everywhere with skeletons. +- **Acceptance check:** No long-lived `—` placeholders in signed-in dashboard. + +### F-027 — Savings withdraw recipient editable +- **Area:** frontend/ux-risk +- **Evidence:** Withdraw flow +- **Impact:** User can fat-finger funds to wrong ID. +- **Fix direction:** Lock recipient to resolved user; explicit "change" flow. +- **Acceptance check:** Cannot submit withdraw to different ID without extra confirmation. + +### F-051 — Signup passcode minimum too weak +- **Area:** frontend/auth +- **Evidence:** `acbu-frontend/app/auth/signup/page.tsx` +- **Impact:** 4-digit passcode easy to brute locally. +- **Fix direction:** Align with backend policy; enforce entropy meter. +- **Acceptance check:** Cannot sign up with weak passcode in prod config. + +### F-063 — Environment base URL misconfiguration footgun +- **Area:** frontend/config +- **Evidence:** `acbu-frontend/lib/api/client.ts` error message +- **Impact:** POSTs hit Next.js and return 405 confusingly. +- **Fix direction:** Add startup runtime check in layout for missing `NEXT_PUBLIC_API_BASE_URL`. +- **Acceptance check:** Dev console shows loud misconfig banner if unset. + +--- + +## 5. Medium Severity Issues (🟡) + +### F-007 — Dual Authorization + x-api-key headers +- **Area:** frontend/api · **Evidence:** `acbu-frontend/lib/api/client.ts` +- **Impact:** Redundant secret channels increase accidental logging by proxies. +- **Fix direction:** Send only one header per backend contract; document. +- **Acceptance check:** Proxy logs never contain duplicate secret lines. + +### F-009 — CSRF cookie read without backend pairing guarantee +- **Area:** frontend/security · **Evidence:** `acbu-frontend/lib/api/client.ts` (`getCsrfToken`) +- **Impact:** If backend never sets `XSRF-TOKEN`, code becomes dead. +- **Fix direction:** Align with backend double-submit cookie; remove if dead. +- **Acceptance check:** Cross-site POST cannot succeed against prod API. + +### F-012 — No `test` / `typecheck` scripts in frontend +- **Area:** frontend/qa · **Evidence:** `acbu-frontend/package.json` +- **Impact:** No default CI quality gate beyond lint. +- **Fix direction:** Add `pnpm typecheck` + Playwright smoke + component tests for money forms. +- **Acceptance check:** CI runs typecheck + smoke on PR. + +### F-013 — Both `package-lock.json` and `pnpm-lock.yaml` +- **Area:** frontend/devx · **Evidence:** `acbu-frontend/` lockfiles +- **Impact:** Dependency drift between contributors. +- **Fix direction:** Pick one package manager; delete the other lockfile. +- **Acceptance check:** Single lockfile policy enforced in CI. + +### F-016 — Savings New Goal button inert +- **Area:** frontend/feature · **Evidence:** `acbu-frontend/app/(app)/savings/page.tsx` +- **Impact:** Broken CTA erodes trust. +- **Fix direction:** Implement goal model or hide until ready. +- **Acceptance check:** Button either works or is absent. + +### F-017 — SME CTAs inert +- **Area:** frontend/feature · **Evidence:** `acbu-frontend/app/(app)/sme/page.tsx` +- **Impact:** Lead gen dead end. +- **Fix direction:** Hook to application API or remove. +- **Acceptance check:** Click leads to real flow or mailto with tracking. + +### F-024 — AFK vs ACBU naming drift +- **Area:** frontend/copy · **Evidence:** Multiple pages (`mint`, `send`, `home`) +- **Impact:** Confusing brand + reconciliation errors. +- **Fix direction:** Single glossary constant exported to UI. +- **Acceptance check:** Grep shows no `AFK` in user-visible prod strings (if policy is ACBU-only). + +### F-026 — Savings page mixes mock cards with API data +- **Area:** frontend/data · **Evidence:** `acbu-frontend/app/(app)/savings/page.tsx` +- **Impact:** Totals disagree with chain truth. +- **Fix direction:** Remove mock constants; derive from API only. +- **Acceptance check:** Totals equal sum(positions). + +### F-028 — Hardcoded fees on mint UI +- **Area:** frontend/mint · **Evidence:** `acbu-frontend/app/(app)/mint/page.tsx` +- **Impact:** Misleading fee → compliance complaints. +- **Fix direction:** Fetch fee schedule from backend. +- **Acceptance check:** Fee matches backend quote within rounding. + +### F-029 — Me page KYC badge static +- **Area:** frontend/me · **Evidence:** `acbu-frontend/app/(app)/me/page.tsx` +- **Impact:** Users misjudge what they can do. +- **Fix direction:** Bind badge to KYC status endpoint. +- **Acceptance check:** Badge updates after KYC webhook simulation. + +### F-030 — Me page hardcoded stats +- **Area:** frontend/me · **Evidence:** `acbu-frontend/app/(app)/me/page.tsx` +- **Impact:** Trust-breaking mock wealth numbers. +- **Fix direction:** Replace with API-driven aggregates. +- **Acceptance check:** Stats match backend for seeded user. + +### F-032 — International/Gateway stubs +- **Area:** frontend/nav · **Evidence:** `international` + `gateway` pages +- **Impact:** Dead nav items frustrate users. +- **Fix direction:** Hide behind feature flags until backend ready. +- **Acceptance check:** Nav only lists shipped features. + +### F-036 — Send note omitted from confirm + API +- **Area:** frontend/transfers · **Evidence:** `acbu-frontend/app/(app)/send/page.tsx` +- **Impact:** Compliance reference lost for transfers. +- **Fix direction:** Plumb `note` to API + receipts. +- **Acceptance check:** PDF/email receipt shows note. + +### F-037 — Inconsistent API error UX across pages +- **Area:** frontend/quality · **Evidence:** Many `app/(app)/**` pages +- **Impact:** Users see generic failures on money errors. +- **Fix direction:** Shared `useApiError` hook mirroring burn page. +- **Acceptance check:** All money pages map 429/503/402 consistently. + +### F-038 — Silent catch on send loads +- **Area:** frontend/reliability · **Evidence:** `send/page.tsx` `.catch(() => {})` patterns +- **Impact:** Broken lists look empty vs errored. +- **Fix direction:** Surface toast + retry. +- **Acceptance check:** Failed load shows error state with retry. + +### F-039 — No React error boundary +- **Area:** frontend/reliability · **Evidence:** `acbu-frontend/app/layout.tsx` +- **Impact:** Single component error whitescreens app. +- **Fix direction:** Add route-level error boundaries + reporting. +- **Acceptance check:** Forced error shows fallback UI not blank page. + +### F-040 — useEffect dependency hazards (send/contacts/guardians/kyc) +- **Area:** frontend/react · **Evidence:** Multiple pages +- **Impact:** Stale data or infinite loops when deps fixed naively. +- **Fix direction:** Refactor to `useCallback` + exhaustive-deps lint as error. +- **Acceptance check:** ESLint react-hooks passes on money routes. + +### F-046 — Accessibility: labels without htmlFor +- **Area:** frontend/a11y · **Evidence:** Mint/send/burn/withdraw forms +- **Impact:** Screen reader users cannot operate forms reliably. +- **Fix direction:** Pair labels+ids; run axe in CI. +- **Acceptance check:** axe-core critical violations = 0 on money forms. + +### F-047 — Mobile nav icon-only links lack aria-label +- **Area:** frontend/a11y · **Evidence:** `acbu-frontend/components/mobile-nav.tsx` +- **Impact:** Navigation unusable via VoiceOver. +- **Fix direction:** Add concise `aria-label` per route. +- **Acceptance check:** VoiceOver reads destination per icon. + +### F-050 — Burn form lacks strong validation +- **Area:** frontend/forms · **Evidence:** `acbu-frontend/app/(app)/burn/page.tsx` +- **Impact:** Bad bank details fail late or confuse users. +- **Fix direction:** Client-side format hints + server-driven validation messages. +- **Acceptance check:** Invalid bank codes blocked before submit. + +### F-055 — Nested interactive elements (Link in Button) +- **Area:** frontend/html · **Evidence:** `send/page.tsx` Add Contact +- **Impact:** Invalid HTML confuses assistive tech + click targets. +- **Fix direction:** Use `Button asChild` + `Link` or style `Link` as button. +- **Acceptance check:** HTML validator clean for that control. + +### F-062 — Stellar burning client uses `as any` on send response +- **Area:** frontend/stellar · **Evidence:** `acbu-frontend/lib/stellar/burning.ts` +- **Impact:** Missed error branches hide failed txs. +- **Fix direction:** Type Soroban response properly; surface `errorResultXdr`. +- **Acceptance check:** Failed tx always shows human readable Soroban error. + +### F-064 — No Content-Security-Policy for Next app +- **Area:** frontend/security · **Evidence:** `next.config.mjs` headers (missing) +- **Impact:** XSS impact amplified when keys live in sessionStorage. +- **Fix direction:** Add strict CSP nonces via Next middleware. +- **Acceptance check:** CSP report-only phase then enforce. + +--- + +## 6. Low Severity Issues (🟢) + +### F-008 — Client-side global fetch timeout without abort sharing +- **Area:** frontend/api · **Evidence:** `acbu-frontend/lib/api/client.ts` (`AbortController` per call) +- **Impact:** Long hung requests waste battery; duplicated controllers if callers pass signal incorrectly. +- **Fix direction:** Document pattern; optional default timeout env. +- **Acceptance check:** Hung request cancels at configured deadline. + +### F-011 — Package name still `my-v0-project` +- **Area:** frontend/devx · **Evidence:** `acbu-frontend/package.json` (`name`) +- **Impact:** Confusing telemetry, npm metadata, support tickets. +- **Fix direction:** Rename to `acbu-frontend`. +- **Acceptance check:** Published docs reference correct package name. + +### F-031 — Business page hardcoded stats +- **Area:** frontend/business · **Evidence:** `acbu-frontend/app/(app)/business/page.tsx` +- **Impact:** Same trust issue for SMB story. +- **Fix direction:** Wire SME metrics API or mark demo mode clearly. +- **Acceptance check:** Demo mode banner when using mock numbers. + +### F-033 — Help page too thin +- **Area:** frontend/support · **Evidence:** `acbu-frontend/app/me/help/page.tsx` +- **Impact:** Support load spikes. +- **Fix direction:** FAQ + status page links + ticket form. +- **Acceptance check:** Users can self-serve top 10 questions. + +### F-034 — Sign-in label says Username only +- **Area:** frontend/auth · **Evidence:** `acbu-frontend/app/auth/signin/page.tsx` +- **Impact:** Users try wrong identifier format. +- **Fix direction:** Copy: username/email/phone per backend. +- **Acceptance check:** Support tickets about login drop in UAT. + +### F-035 — Signup success query param ignored +- **Area:** frontend/auth · **Evidence:** `acbu-frontend/app/auth/signin/page.tsx` +- **Impact:** Missed positive reinforcement. +- **Fix direction:** Toast/banner on `?created=1`. +- **Acceptance check:** New user sees confirmation once. + +### F-041 — Savings deposit URI length filter too strict +- **Area:** frontend/savings · **Evidence:** `acbu-frontend/app/(app)/savings/deposit/page.tsx` +- **Impact:** Blocks non-Stellar IDs incorrectly. +- **Fix direction:** Align validation with backend recipient resolver. +- **Acceptance check:** Phone-based IDs work where supported. + +### F-042 — `as any` tabs in bills/currency +- **Area:** frontend/types · **Evidence:** `bills/page.tsx`, `currency/page.tsx` +- **Impact:** Weak typing hides invalid tab states. +- **Fix direction:** Discriminated unions for tab state. +- **Acceptance check:** TS strict mode clean for those files. + +### F-043 — console.log in money handlers +- **Area:** frontend/hygiene · **Evidence:** Savings/bills/lending/currency pages +- **Impact:** Leaks PII to browser consoles in prod. +- **Fix direction:** Replace with structured logger behind `DEBUG` flag. +- **Acceptance check:** Prod bundle has no `console.log` in transfer paths. + +### F-044 — Unstable list keys (rates/mint) +- **Area:** frontend/react · **Evidence:** `rates/page.tsx`, `mint/page.tsx` +- **Impact:** UI state bugs on reorder. +- **Fix direction:** Use stable ids from API. +- **Acceptance check:** No `key={index}` for dynamic lists. + +### F-045 — No i18n / localization +- **Area:** frontend/product · **Evidence:** Whole app +- **Impact:** Africa MVP needs multi-locale formatting. +- **Fix direction:** Adopt next-intl or similar; extract strings. +- **Acceptance check:** At least NG/KE locale number formats supported. + +### F-048 — Dark mode badge colors hardcoded light palette +- **Area:** frontend/theme · **Evidence:** `send/page.tsx` status badges +- **Impact:** Poor contrast in dark theme. +- **Fix direction:** Use semantic tokens from design system. +- **Acceptance check:** WCAG AA contrast on badges in dark mode. + +### F-049 — Back navigation pattern inconsistent +- **Area:** frontend/ux · **Evidence:** Multiple pages mix `router.back` vs `Link` +- **Impact:** Users land on unexpected off-app pages. +- **Fix direction:** Prefer explicit `Link` targets within app shell. +- **Acceptance check:** Back never exits app shell unintentionally. + +### F-052 — Send amount missing min attribute +- **Area:** frontend/forms · **Evidence:** `send/page.tsx` +- **Impact:** Negative amounts via keyboard. +- **Fix direction:** `inputMode="decimal"` + `min` + backend validation mirror. +- **Acceptance check:** Negative amounts impossible in UI. + +### F-053 — Activity links wrong route target +- **Area:** frontend/nav · **Evidence:** `activity/page.tsx` +- **Impact:** Users open wrong detail screen. +- **Fix direction:** Link to canonical transaction detail route. +- **Acceptance check:** Deep link opens correct transfer id. + +### F-054 — Me page links 2FA to auth flow not settings +- **Area:** frontend/nav · **Evidence:** `me/page.tsx` +- **Impact:** Confusing security UX loop. +- **Fix direction:** Point to settings-first flow. +- **Acceptance check:** User manages 2FA without re-auth loop. + +### F-056 — Amount formatting inconsistent +- **Area:** frontend/formatting · **Evidence:** Home/transfers lists +- **Impact:** Users misread decimals especially for 7dp assets. +- **Fix direction:** Central `formatAcbu` helper with locale. +- **Acceptance check:** All lists use same formatter. + +### F-057 — Reserves page lacks unit explanations +- **Area:** frontend/education · **Evidence:** `reserves/page.tsx` +- **Impact:** Users misinterpret health metrics. +- **Fix direction:** Tooltips linking to docs `RESERVE_MANAGEMENT`. +- **Acceptance check:** User testing shows improved comprehension. + +### F-058 — Rates page number formatting +- **Area:** frontend/formatting · **Evidence:** `rates/page.tsx` +- **Impact:** Rates as raw strings hard to scan. +- **Fix direction:** Format with significant digits policy. +- **Acceptance check:** Rates match spec precision. + +### F-059 — Burn page currency display locale +- **Area:** frontend/formatting · **Evidence:** `burn/page.tsx` +- **Impact:** NGN formatting not locale-aware. +- **Fix direction:** Use `Intl.NumberFormat`. +- **Acceptance check:** Locale switch changes grouping separators. + +### F-060 — Performance: send page callbacks not memoized +- **Area:** frontend/perf · **Evidence:** `send/page.tsx` +- **Impact:** Extra rerenders on large contact lists. +- **Fix direction:** Memoize handlers + virtualize list. +- **Acceptance check:** React profiler shows acceptable commit times. + +### F-061 — Clipboard API failure on HTTP +- **Area:** frontend/compat · **Evidence:** `receive/page.tsx` +- **Impact:** Copy address fails silently on non-secure origins. +- **Fix direction:** Detect + fallback prompt. +- **Acceptance check:** Copy works on HTTPS and shows message on HTTP. + +### F-065 — No Subresource Integrity for third-party scripts (if any) +- **Area:** frontend/security · **Evidence:** `app/layout` / analytics +- **Impact:** Supply-chain risk if external scripts added. +- **Fix direction:** Prefer first-party hosting; SRI for CDNs. +- **Acceptance check:** Security review checklist item signed off. --- -## Critical +## 7. Legacy 77-Item Origin List (cross-reference) + +The legacy list previously alone at this path was a more recent manual review with slightly different framing. Items are preserved here for traceability; each is tagged `(moved)` (when it cleanly maps to a canonical `F-###` ID) or `(new)` (when it captures a distinct finding that should be merged into the canonical list in a follow-up PR). + +### Critical + +1. **Send success dialog shows empty amount** – app/(app)/send/page.tsx: `setAmount('')` runs before the success dialog. *(moved → F-014)* + +### High – Security + +2. **API key stored in sessionStorage** – *(moved → F-002)* +3. **Challenge token in URL** – *("challenge_token" query param).* *(moved → F-006)* + +### High – Non-functional Flows + +4. **Savings deposit only logs to console** – *(moved → F-015)* +5. **Savings "New Goal" button does nothing** – *(moved → F-016)* +6. **SME "Get Started" / "Apply Now" no handlers** – *(moved → F-017)* +7. **Lending application only logs to console** – *(moved → F-018)* +8. **Currency operations simulate with setTimeout** – *(moved → F-019)* +9. **Bill payment only logs to console** – *(moved → F-020)* +10. **Wallet confirm button disabled forever** – *(moved → F-021)* +11. **Security settings placeholder** – *(moved → F-022)* +12. **Mint page Burn tab non-functional** – *(moved → F-023)* + +### Medium – UX/Design + +13. **AFK vs ACBU naming inconsistency** – *(moved → F-024)* +14. **Balance always placeholder** – *(moved → F-025)* +15. **Savings: mock data mixed with API** – *(moved → F-026)* +16. **Savings withdraw: user field confusing** – *(moved → F-027)* +17. **Hardcoded fees and placeholder copy** – *(moved → F-028)* +18. **Me page KYC badge always "Pending"** – *(moved → F-029)* +19. **Me page balance and stats hardcoded** – *(moved → F-030)* +20. **Business page stats hardcoded** – *(moved → F-031)* +21. **Burn tab shows unhelpful text** – app/(app)/mint/page.tsx: copy on the Burn tab. The fake-success flow is captured by F-023; this entry covers the unimplemented / unclear copy. *(see F-023; F-023 covers the fake-success side, this covers the copy side)* +22. **International / gateway pages are stubs** – *(moved → F-032)* +23. **Help page minimal** – *(moved → F-033)* +24. **Sign-in identifier label misleading** – *(moved → F-034)* +25. **`?created=1` from signup ignored** – *(moved → F-035)* +26. **Confirm dialog does not show note** – *(moved → F-036)* +27. **Send note never sent to API** – *(moved → F-036)* + +### Medium – Error Handling + +28. **Consistent API error handling missing** – *(moved → F-037)* +29. **loadTransfers / loadContacts swallow errors** – *(moved → F-038)* +30. **getReceive errors ignored** – Cross-cuts F-038 + F-037. *(moved → F-038 + F-037)* +31. **No error boundary** – *(moved → F-039)* +32. **No CSRF protection** – *(moved → F-009)* + +### Medium – State Management + +33. **useEffect missing opts in dependency array (send)** – *(moved → F-040)* +34. **Infinite loop risk in contacts page** – *(moved → F-040)* +35. **Infinite loop risk in guardians page** – *(moved → F-040)* +36. **useEffect missing opts in KYC page** – *(moved → F-040)* +37. **Savings deposit user filter too strict** – *(moved → F-041 + F-075)* + +### Medium – Code Quality + +38. **`as any` usage in currency page** – *(moved → F-042)* +39. **`as any` usage in bills page** – *(moved → F-042)* +40. **console.log left in production code** – *(moved → F-043)* +41. **Index used as key in lists** – *(moved → F-044)* +42. **No i18n / localization** – *(moved → F-045)* + +### Low – Accessibility + +43. **Form labels and accessibility** – *(moved → F-046)* +44. **Nav links lack aria-labels** – *(moved → F-047)* +45. **Password toggle has no aria-label** – Cross-cuts F-047. *(moved → F-047)* +46. **Burn back link icon-only** – Cross-cuts F-047. *(moved → F-047)* +47. **Send detail back link icon-only** – Cross-cuts F-047. *(moved → F-047)* +48. **Settings cards missing aria-label** – Cross-cuts F-047. *(moved → F-047)* -1. **Send success dialog shows empty amount** – app/(app)/send/page.tsx: `setAmount('')` runs before the success dialog is shown, so the dialog displays "AFK " with no value. Keep amount in state until the dialog is closed. +### Low – Design Consistency -## High – Security +49. **Empty and loading states inconsistent** – Cross-cuts F-049 + a missing `Skeleton` primitive. **Distinct finding; promote to F-066 in a follow-up canonical PR.** *(new — propose F-066)* +50. **Status badge colours in dark mode** – *(moved → F-048)* +51. **Back button pattern inconsistent** – *(moved → F-049)* -2. **API key stored in sessionStorage** – contexts/auth-context.tsx: API key is stored in `sessionStorage`; persists across tabs and is vulnerable to XSS. Prefer `httpOnly` cookies or short-lived tokens. -3. **Challenge token in URL** – app/(public)/auth/2fa/page.tsx: `challenge_token` is passed as a URL query parameter. It can leak via Referer headers, browser history, and server logs. +### Low – Forms -## High – Non-functional Flows +52. **Burn form fields missing maxLength and validation** – *(moved → F-050)* +53. **Signup passcode minimum too weak** – *(moved → F-051)* +54. **Send amount allows negative via keyboard** – *(moved → F-052)* +55. **Contact inputs have no maxLength** – Cross-cuts F-052 + new maxLength checks; **distinct finding, propose F-067.** *(new — propose F-067)* +56. **Profile inputs have no maxLength or format validation** – **Distinct finding, propose F-068.** *(new — propose F-068)* +57. **Recipient input has no maxLength** – Cross-cuts F-067. *(moved → F-067)* + +### Low – Navigation + +58. **Activity links to /send/${id} instead of /transactions/${id}** – *(moved → F-053)* +59. **"Two-Factor Auth" links to auth flow** – *(moved → F-054)* +60. **Nested interactive elements** – *(moved → F-055)* + +### Low – Data Display + +61. **Transfer amounts not formatted** – *(moved → F-056)* +62. **Mock "Total Savings" mixed with API balance** – *(moved → F-026)* +63. **Currency balance misleading** – Cross-cuts F-026. *(moved → F-026)* +64. **Reserve data lacks context** – *(moved → F-057)* +65. **Rate displayed without formatting** – *(moved → F-058)* +66. **Currency shown without locale** – *(moved → F-059)* + +### Low – Performance + +67. **loadTransfers / loadContacts not memoized** – *(moved → F-060)* +68. **Icons recreated each render** – **Distinct finding, propose F-069.** *(new — propose F-069)* +69. **Menu items use router.push instead of Link** – **Distinct finding, propose F-070.** *(new — propose F-070)* + +### Trivial + +70. **Clipboard API may fail on HTTP** – *(moved → F-061)* +71. **Toast removal delay is ~17 minutes** – `TOAST_REMOVE_DELAY = 1000000`. **Distinct finding, propose F-071.** *(new — propose F-071)* +72. **Mobile detection treats "unknown" as desktop** – **Distinct finding, propose F-072.** *(new — propose F-072)* +73. **Post-KYC upload navigation uses uncleaned setTimeout** – **Distinct finding, propose F-073.** *(new — propose F-073)* +74. **Silent username normalization on signup** – `lib/api/auth.ts` lowercases + strips whitespace without warning UI. **Distinct finding, propose F-074.** *(new — propose F-074)* +75. **Auto-fill heuristic requires length >= 56** – **Distinct finding, propose F-075.** *(new — propose F-075)* — note: this overlaps the older F-041 but addresses a different code path (lending + savings auto-fill, not URI-length filter). +76. **API fetch has no timeout** – Frontend `request()` uses `fetch` with no default timeout. **Distinct finding, propose F-076.** *(new — propose F-076)* +77. **/p2p is client-side redirect only** – `app/(app)/p2p/page.tsx` does `useEffect -> router.replace('/send')`. **Distinct finding, propose F-077.** *(new — propose F-077)* + +> **Reconciliation policy:** When a follow-up audit pass opens a new canonical ID for items tagged `(new)`, the row is migrated forward and the tagged comment block in this section is updated to point at the new ID. New IDs are expected to land in `F-066+` and `F-071..F-076` should preserve backward-reference to this section so future readers can trace provenance. + +--- + +## 8. Resolution Tracker (Fix Status) + +> **Format:** `ID · title · status · linked PR / commit · owner` +> +> **Forward-looking template.** Every item is currently 🟡 Open; uniformity of status reflects the state of the working backlog. When a fix merges, the row transitions to ✅ Fixed with a PR link. Example anchors below show what a real fixed row looks like. + +| ID | Title | Status | Notes | +|----|-------|--------|-------| +| _(example)_ | _(example anchor for prior documentary PRs — PR #14 closed issue #1, PR #22 closed #12, PR #23 backend, PR #24 master-index)_ | ✅ Fixed (PR #24 merged) | Documentary PR — not a code fix; historical anchor | +| F-001..F-005 | _Critical cluster_ | 🟡 Open (ship blockers) | Track with TypeScript / wallet / auth refactor | +| F-006, F-010, F-014..F-023, F-025, F-027, F-051, F-063 | _High cluster (14 items)_ | 🟡 Open | Next.js auth + feature-flag workstream | +| F-007, F-009, F-012, F-013, F-016, F-017, F-024, F-026, F-028–F-030, F-032, F-036–F-040, F-046, F-047, F-050, F-055, F-062, F-064 | _Medium cluster (23 items)_ | 🟡 Open | Quality / a11y / hardening workstream | +| F-008, F-011, F-031, F-033..F-035, F-041..F-045, F-048..F-049, F-052..F-054, F-056..F-061, F-065 | _Low cluster (23 items)_ | 🟡 Open | Polish / formatting / docs workstream | + +> **Status legend** — 🟢 Trivial/cosmetic · 🟡 Open (tracked) · 🔵 In review · ✅ Fixed (PR linked) +> +> **Reminder when updating:** When an external PR closes an issue, replace `🟡 Open` with `✅ Fixed` and append the merged PR link in the Notes column. Do not rewrite history; the row itself is the audit trail. + +--- + +## 9. Cross-Reference Map + +| Document | Relationship to this file | +|----------|---------------------------| +| [`../../issues/frontend.md`](../../issues/frontend.md) | **Live triage-ready catalog.** Same IDs and severities; entries are condensed for daily use. | +| [`../../issues/MASTER_INDEX.md`](../../issues/MASTER_INDEX.md) | Master index across backend/frontend/contracts backlogs; Top 20 ship-safety list with per-row tracker pointers. | +| [`../../issues/contracts.md`](../../issues/contracts.md) | Smart contracts MVP issues (C-001..C-060). | +| [`../../issues/backend.md`](../../issues/backend.md) | Backend MVP issues (B-001..B-075). | +| [`../CONTRACTS_ISSUES.md`](../CONTRACTS_ISSUES.md) | Companion long-form reference for smart contracts (PR #22). | +| [`../BACKEND_ISSUES.md`](../BACKEND_ISSUES.md) | Companion long-form reference for backend (PR #23). | +| [`../API_AND_CONTRACTS_REFERENCE.MD`](../API_AND_CONTRACTS_REFERENCE.MD) | API surface map; front-end integration anchors. | +| [`../PROJECT_STRUCTURE.MD`](../PROJECT_STRUCTURE.MD) | Repo layout (where the frontend source lives). | +| [`../../USER_EXPERIENCE/USER_FLOWS.MD`](../../USER_EXPERIENCE/USER_FLOWS.MD) | UX flows context for F-015, F-018–F-020 (console-only features). | +| [`../../USER_EXPERIENCE/MOBILE_OPTIMIZATION_COMPLETE.md`](../../USER_EXPERIENCE/MOBILE_OPTIMIZATION_COMPLETE.md) | Mobile-first context for F-047 (mobile nav a11y) and F-072. | +| [`../../USER_EXPERIENCE/DIASPORA_REMITTANCES.MD`](../../USER_EXPERIENCE/DIASPORA_REMITTANCES.MD) | Diaspora remittance context for F-019, F-020, F-032. | +| [`../../SECURITY_GUIDE.MD`](../../SECURITY_GUIDE.MD) | Security posture context for F-001..F-005 + F-064 + F-065. | +| [`../../correction.md`](../../correction.md) | Standing list of items curated for fast triage (frontend visibility gaps). | + +--- + +## 10. Top Remediations (ship-safety order) + +Order these fixes in the MVP launch runbook before deploying production: + +1. **F-001..F-005** — Hard wallet + auth + build pipeline overhaul: turn off `ignoreBuildErrors`, move secrets off sessionStorage, replace base64 with AES-GCM, block plaintext wallet path. +2. **F-002 / F-003 / F-005** — Single PR for the wallet secrets stack (migrate to WebCrypto keys, kill plaintext store, add sessionStorage lint rule). +3. **F-022 / F-039 / F-064** — Settings-first security surface + global error boundary + CSP baseline. +4. **F-014 / F-015 / F-018 / F-019 / F-020 / F-022 / F-023 / F-021** — Stubbed feature clean-up: savings deposit, lending application, currency operations, bills payment, security settings, mint/burn tab, wallet confirm. +5. **F-025 / F-027 / F-051 / F-063** — Data integrity + auth strength + environment footgun. +6. **F-006 / F-010 / F-046 / F-047** — Auth/secrets hygiene + accessibility on money routes. +7. **F-040 / F-039 / F-038 / F-037** — Quality + reliability pass (react-hooks lint, error boundaries, retry UI, useApiError hook). +8. **F-007 / F-009 / F-012 / F-013** — Dev infrastructure (single header, CSRF pairing, typecheck/smoke CI, single lockfile). +9. **F-016 / F-017 / F-032 / F-033 / F-034 / F-035** — Feature-flag and copy cleanups (inert CTAs, dead nav, sign-in label, signup confirmation). +10. **F-008 / F-011 / F-031 / F-041..F-065** — Polish + tooling (timeouts, package rename, demo-mode banners, format/locale helpers, accessibility polish). + +--- + +## 11. Maintenance + +- **New issues** — Add to `issues/frontend.md` first (canonical triage). Mirror to this file with the next stable `F-###` ID. +- **Closed fixes** — Promote the fix to `✅ Fixed (PR linked)` in Section 8 and link to the merged PR. +- **Legacy `(new)` items in Section 7** — Open a follow-up canonical-ID PR; on merge, update both `issues/frontend.md` and this file. +- **Cross-doc references** — Update `issues/MASTER_INDEX.md` summary counts (Top 20 pointer list) when severities change. + +--- + +## Related Documents + +- [Live frontend issue catalog](../../issues/frontend.md) +- [Master backlog index](../../issues/MASTER_INDEX.md) +- [Contracts long-form reference](../CONTRACTS_ISSUES.md) +- [Backend long-form reference](../BACKEND_ISSUES.md) +- [Smart contract spec (root copy)](../SMART_CONTRACT_SPEC.md) +- [Project structure map](../PROJECT_STRUCTURE.md) +- [User flows](../../USER_EXPERIENCE/USER_FLOWS.md) +- [Security guide](../../SECURITY_GUIDE.md) + +--- -4. **Savings deposit only logs to console** – app/(app)/savings/page.tsx: `handleConfirmDeposit` only `console.log`s; no API call is made. -5. **Savings "New Goal" button does nothing** – app/(app)/savings/page.tsx: The button has no handler. -6. **SME "Get Started" and "Apply Now" have no handlers** – app/(app)/sme/page.tsx: Buttons are non-functional. -7. **Lending application only logs to console** – app/(app)/lending/page.tsx: `handleSubmitApplication` only `console.log`s; no API call. -8. **Currency operations simulate with setTimeout** – app/(app)/currency/page.tsx: Mint/Burn/International operations only simulate with `setTimeout`; no real API calls. -9. **Bill payment only logs to console** – app/(app)/bills/page.tsx: Payment handler only `console.log`s; no API call. -10. **Wallet confirm button disabled forever** – app/(app)/me/settings/wallet/page.tsx: "Confirm wallet" button is disabled with no implementation path. -11. **Security settings is a placeholder** – app/(app)/me/settings/security/page.tsx: Shows placeholder text "2FA and delete account options. Will wire to API." -12. **Mint page Burn tab non-functional** – app/(app)/mint/page.tsx: The Burn tab does not call the burn API; confirm step only sets success after a timeout. - -## Medium – UX/Design - -13. **AFK vs ACBU naming inconsistency** – Mint page and home use "AFK"; burn and other copy use "ACBU". Standardise product name across all labels, headers, and empty states. -14. **Balance always placeholder** – Balance is shown as "—" or "AFK —" on mint, send, home, and savings; no real balance API is wired. -15. **Savings: mock data mixed with API** – Savings page mixes API data (positions balance) with hardcoded cards (savingsAccounts, mockGoals with fixed dates). "Total Savings" and interest are static. -16. **Savings withdraw: user field confusing** – Withdraw page pre-fills "User (Stellar address or ID)" from getReceive but leaves it editable; users could change it and withdraw to the wrong account. -17. **Hardcoded fees and placeholder copy** – Mint burn card shows "Processing Fee: AFK 1.00"; network fee shows "See quote". Either compute from API or mark as estimate. -18. **Me page KYC badge always "Pending"** – app/(app)/me/page.tsx: KYC badge always shows "Pending" regardless of real status. -19. **Me page balance and stats hardcoded** – app/(app)/me/page.tsx: "AFK 12,450" and "This Month +AFK 2,340" are hardcoded, not from API. -20. **Business page stats hardcoded** – app/(app)/business/page.tsx: "Monthly Volume AFK 145,320" and "Employees 24" are hardcoded mock data. -21. **Burn tab shows unhelpful text** – app/(app)/mint/page.tsx: Burn tab shows "Local currency (see /burn for details)" — unclear UX that sends users elsewhere. -22. **International and gateway pages are stubs** – app/(app)/international/page.tsx and app/(app)/gateway/page.tsx: Show "Coming soon" with no CTA or timeline. -23. **Help page minimal** – app/(app)/me/help/page.tsx: Only shows "support@acbu.io" with no FAQs or support flow. -24. **Sign-in identifier label misleading** – Label says "Username" but backend accepts username, email, or E.164 phone. Use "Username, email, or phone". -25. **`?created=1` from signup ignored** – app/(public)/auth/signin/page.tsx: Query param from signup is never shown as a success message. -26. **Confirm dialog does not show note** – app/(app)/send/page.tsx: Note is collected but not shown in the confirm dialog. -27. **Send note never sent to API** – app/(app)/send/page.tsx: `note` is collected but never passed to `createTransfer` API. - -## Medium – Error Handling - -28. **Consistent API error handling missing** – burn/page.tsx handles ApiError with status-specific messages; ensure all other API-calling pages use the same pattern. -29. **loadTransfers and loadContacts swallow errors** – app/(app)/send/page.tsx: `.catch(() => {})` silently ignores failures. -30. **getReceive errors ignored** – app/(app)/savings/page.tsx: userApi.getReceive errors are swallowed. -31. **No error boundary** – app/layout.tsx: No React error boundary; uncaught errors can crash the entire app. -32. **No CSRF protection** – lib/api/client.ts: No CSRF token for state-changing requests. - -## Medium – State Management - -33. **useEffect missing opts in dependency array** – app/(app)/send/page.tsx: `useEffect` depends on `opts.token` but calls `loadTransfers`/`loadContacts` that use full `opts` object; `opts` is not in deps. -34. **Infinite loop risk in contacts page** – app/(app)/me/settings/contacts/page.tsx: `load` used in `useEffect` but not in deps; if added, would cause infinite loop. Use `useCallback`. -35. **Infinite loop risk in guardians page** – app/(app)/me/settings/guardians/page.tsx: Same pattern. -36. **useEffect missing opts in KYC page** – app/(app)/me/kyc/page.tsx: `opts` missing from dependency array. -37. **Savings deposit user filter too strict** – app/(app)/savings/deposit/page.tsx: `uri.length >= 56` filters out non-Stellar addresses; may block valid user IDs. - -## Medium – Code Quality - -38. **`as any` usage in currency page** – app/(app)/currency/page.tsx: `as any` used for tab value. -39. **`as any` usage in bills page** – app/(app)/bills/page.tsx: `as any` used for tab value. -40. **console.log left in production code** – app/(app)/savings/page.tsx, bills/page.tsx, lending/page.tsx, currency/page.tsx: `console.log` calls left in handlers. -41. **Index used as key in lists** – app/(app)/mint/page.tsx and app/(app)/rates/page.tsx: Rates lists use array index as `key` prop instead of a stable identifier. -42. **All user-facing strings hardcoded** – Entire codebase: No i18n support; all text is in English with no extraction or translation framework. - -## Low – Accessibility - -43. **Form labels and accessibility** – Many forms use `