# Cash wallet — 9 September 2026

The wallet now has one cash balance with toman and rial display units, an available/locked breakdown, a deposit amount form, and private payment history at `/wallet/deposit`. Gateway payment remains disabled until a provider accepts the business and a merchant adapter is configured. No real payment has been requested or credited during setup.

## Accounting

- `marketplace_private.asset_positions` stores new cash in `IRR`, as whole rials. One toman equals ten rials. Existing legacy `TMN` balances remain intact and are included once in the cash display and trading balance calculation.
- Migration `202609080008_cash_wallet.sql` creates a zero-rial position for existing marketplace accounts and for new marketplace registrations. It never resets an existing position or grants promotional money.
- Project token valuations are not spendable cash. Locked cash is excluded from the available balance. Missing or invalid balance data is shown as unavailable, not zero.
- `fiat_payment_intents` records each request and its provider status. `fiat_deposit_ledger` records one credit per verified payment. A credited payment also creates a confirmed transaction and notification, in the same database transaction as its balance update.

## Provider integration contract

The current browser API returns `enabled: false` for the gateway. Its POST route can save drafts, cancel drafts and submit unverified manual-transfer claims; none of those creates a payment intent, redirects to a gateway, or changes a balance. The following database operations are available only to the server service role:

1. `marketplace_deposit_create` requires a verified contact, a unique request ID, an integer rial amount, provider and merchant identifiers. Retries must use the same values. Requests are bounded per user. `test_mode` defaults to true.
2. After a provider request succeeds, bind its authority to the stored intent using `marketplace_deposit_bind`.
3. The future server callback must independently verify the payment with that provider, including the expected merchant, authority, rial amount, successful settlement state, and receipt. Callback query parameters and browser success flags are not proof.
4. Only after successful verification may the server call `marketplace_deposit_credit`. It rejects sandbox payments, mismatched authorities/amounts, cancelled payments, conflicting receipts, and duplicate receipt use. Retrying an already credited payment with the same receipt is idempotent.

Do not activate payment before implementing provider-specific verification, expiry/failure handling, reconciliation of uncertain results, and the merchant's agreed deposit limits. API credentials belong in server secrets, never client environment variables or the merchant identifier field. A provider adapter, withdrawals, refunds/reversals, and real trading settlement are outside this foundation and are not active.

## Access

Both new tables have RLS enabled and no anonymous or authenticated direct access. The authenticated history RPC derives the account from `auth.uid()` and returns only its latest 100 payments, without merchant identifiers or gateway authorities. There is no user-accessible balance mutation.

## Provider shortlist

Initial preference: [Zibal](https://zibal.ir/ipg), for its gateway and financial products including split settlement and refunds to the original card. [Vandar](https://vandar.io/) is an alternative for payouts, direct debit and identity services. These are product-fit suggestions, not confirmation that either provider accepts Planck's tokenized-investment and wallet-funding business.

[Zarinpal's terms](https://www.zarinpal.com/terms) restrict several money, securities and financial-voucher activities, so acceptance of this specific model must not be assumed. Describe the actual wallet-funding and project-token use case to the selected provider and obtain acceptance before connecting production payments.

## Verification

The test suite checks zero opening balances, preservation of legacy balances, signup/referral trigger coexistence, access isolation, exact currency conversion, locked balances, service-only funding, duplicate/concurrent callbacks, conflicting receipts, sandbox rejection, and a forged browser success flag. Positive funding tests run only in an isolated local PostgreSQL-compatible database.

## Toman deposit screen — 30 September 2026

`/wallet/deposit` now provides Toman/crypto tabs, whole-toman input with Persian digit grouping, 5/10/15/25 million presets, six method cards (gateway first and disabled), FAQ, bank-account link and paginated request history. `/wallet/deposit?tab=token` opens digital-asset addresses. Destination accounts are configured by the owner with MFA at admin → اتصال‌ها → واریز تومان و حساب‌های مقصد. Defaults contain no receiving bank information and all methods remain unavailable for payment until configured. Instant-bank and direct-debit adapters remain disconnected.

Migration `202609300005_toman_deposit_requests.sql` adds private destinations, immutable configuration versions and retained customer requests. Every explicit save, changed save, cancellation and transfer submission creates a customer activity entry visible/searchable in the admin profile. Retrying an unchanged operation does not duplicate it. Request UUIDs, versions, amount bounds and rate limits are enforced in PostgreSQL. Whole rials are transported as strings. Requests are user-scoped with no direct client table grants, and suspended/closed accounts cannot use the RPCs.

Manual submission requires a current verified identity and verified bank ownership; card transfer also requires verified card linkage. It binds a reviewed destination version, source-bank snapshot and unique bank reference. `submitted` means awaiting reconciliation, never a confirmed payment. Generic profile/activity approval cannot approve these financial claims, and it cannot credit money. There is no manual-claim settlement adapter yet; configure actual receiving details only when an operational reconciliation process is available. Gateway funding still uses the separate verified payment ledger described above.

The new UI/API/DB tests cover authorization, same-origin mutation, exact amount conversion, double-click/retry idempotency, stale versions, ownership checks, destination changes, cancellation retention and unchanged cash-credit behavior. They use isolated fixtures, never real payments.

Deployment: migrations 005 and 006 were applied to Supabase project `wlsxzyeernwtsetzyltq` on 30 September 2026. Catalog checks confirmed all six RPCs, RLS on all three new tables and three disabled empty receiving-account configurations. Compatibility migration 006 adds only missing bank evidence columns for older installations; it never marks legacy bank ownership or card linkage verified. No real payment, balance credit or customer test request was created during this work.
