# Implementation notes

## Status lifecycle

Invoice: `waiting -> detected -> confirming -> confirmed -> finished`; alternate terminal states: `expired`, `cancelled`, `failed`.

Payout: `pending_approval -> approved -> broadcasting -> confirming -> completed`; alternate terminal states: `rejected`, `cancelled`, `failed`.

## Payment confirmation posting

For a 50 USDT payment and 0.25 USDT fee:

- debit platform `blockchain_clearing`: 50,000,000
- credit merchant `merchant_available`: 49,750,000
- credit platform `platform_fee_revenue`: 250,000

Before sufficient confirmations, post to `merchant_pending`; at confirmation, move from pending to available in a second balanced ledger transaction.

## Mandatory processing order

1. Authenticate provider webhook.
2. Deduplicate provider event.
3. Store raw event unchanged.
4. Normalize into chain transaction.
5. Validate environment/network/token contract/decimals/destination.
6. Enforce unique `(network, tx_hash, transfer_index)`.
7. Independently query transaction/confirmations.
8. Allocate to invoice under row lock.
9. Update invoice aggregate and state.
10. Post balanced ledger transaction.
11. Insert merchant webhook event/outbox record in the same DB transaction.
12. Dispatch delivery after commit.

## Security gaps to complete before production

- Replace Laravel encrypted cast with cloud KMS envelope encryption and explicit key IDs.
- Add TOTP verification service; the payout controller currently checks only whether 2FA is enabled.
- Add payout destination allowlist and cooling period.
- Add admin/operator guards, roles, approval quorum, and step-up authentication.
- Add provider-specific webhook signature/IP validation.
- Add API scope middleware.
- Add database-level protection preventing UPDATE/DELETE on posted ledger entries.
- Add transactional outbox table for all queue dispatches.
