new-site/api/migrations/062_crypto_payment_ledger.sql
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

53 lines
3.6 KiB
SQL

-- 062: Crypto payment ledger — immutable money ledger
--
-- Every crypto→USD movement writes one row here: the initial SHKeeper
-- receive, any mid-path swaps (e.g. ETH→USDC), the Coinbase Prime
-- offramp, the Relay bank deposit, card authorizations + settlements,
-- and cold-wallet sweeps. Rows are never mutated after creation —
-- corrections use a `movement_type='adjustment'` or `'reversal'` entry
-- that links via related_ledger_id.
--
-- This table is the source of truth for IRS Form 8949 cost-basis
-- reconciliation: every `receive` captures acquired_at + fx_rate_usd
-- (cost basis); every `offramp` captures disposed_at + proceeds_usd.
CREATE TABLE IF NOT EXISTS crypto_payment_ledger (
id BIGSERIAL PRIMARY KEY,
order_id TEXT NOT NULL,
order_type TEXT NOT NULL, -- compliance | formation | canada_crtc | bundle
coin TEXT NOT NULL, -- BTC | ETH | MATIC | LTC | TRX | BNB | DOGE | USDC | USD
movement_type TEXT NOT NULL CHECK (movement_type IN (
'receive', -- customer → SHKeeper (ledger entry on webhook confirm)
'swap', -- within exchange, coin → coin (e.g., ETH → USDC)
'offramp', -- coin → USD via Coinbase Prime market-sell
'bank_deposit', -- USD arrival at RelayFi (matched from IMAP monitor)
'card_authorization', -- Relay debit card auth event (card_settlement follows)
'card_settlement', -- Relay debit card final posting
'sweep', -- hot → cold wallet transfer
'reversal', -- corrective entry undoing a prior row
'adjustment' -- manual accounting correction
)),
amount_coin NUMERIC(36,18), -- signed; +in, -out. NULL for USD-only rows.
amount_usd_cents BIGINT NOT NULL, -- signed USD-equivalent at entry time
fx_rate_usd NUMERIC(24,10), -- coin→USD rate captured at entry
basis_usd_cents BIGINT, -- cost basis for disposal rows (FIFO)
proceeds_usd_cents BIGINT, -- proceeds for disposal rows
acquired_at TIMESTAMPTZ, -- when this coin was originally received (receive rows)
disposed_at TIMESTAMPTZ, -- when this coin was sold (offramp rows)
provider TEXT, -- shkeeper | coinbase_prime | relay
provider_ref TEXT, -- tx hash | Prime order id | Relay tx id
provider_status TEXT,
state TEXT NOT NULL DEFAULT 'pending'
CHECK (state IN ('pending','confirmed','failed','reversed')),
idempotency_key TEXT UNIQUE, -- e.g. "shkeeper:<txid>" | "prime:<order>" | "sweep:<id>"
related_ledger_id BIGINT REFERENCES crypto_payment_ledger(id),
notes TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_cpl_order ON crypto_payment_ledger (order_id);
CREATE INDEX IF NOT EXISTS idx_cpl_pending ON crypto_payment_ledger (state) WHERE state = 'pending';
CREATE INDEX IF NOT EXISTS idx_cpl_disposal ON crypto_payment_ledger (disposed_at) WHERE disposed_at IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_cpl_movement_type ON crypto_payment_ledger (movement_type);
CREATE INDEX IF NOT EXISTS idx_cpl_provider_ref ON crypto_payment_ledger (provider, provider_ref) WHERE provider_ref IS NOT NULL;