import type { Pool, PoolClient } from 'pg'; import { IS_PILOT, NETWORK } from '../../shared/network.ts'; import { CHAIN_ID } from '../testnet/consensus.ts'; import { CUSTODY_WRITE_LOCK, verifyCustodySchema } from './postgres-schema.ts'; export type PilotCustodyIdentity = { version: 1; mode: 'pilot-custody'; policy: 'pilot-custody-v1'; marketNetwork: 'wikideck-randomx-pilot-1'; marketChainId: string; moneroNetwork: 'mainnet'; custodianId: string; activationStatus: 'identity-only'; initializedAt: number; }; function validUuid(value: string): boolean { return /^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$/i.test(value); } function requirePilot(custodianId: string, initializedAt: number): void { if (!IS_PILOT || NETWORK !== 'wikideck-randomx-pilot-1' || !validUuid(custodianId)) { throw new Error('Pilot custody identity requires the pilot profile and a valid custodian UUID'); } if (!Number.isSafeInteger(initializedAt) || initializedAt < 0) throw new Error('Invalid pilot identity initialization time'); } export function pilotCustodyIdentityFromRow(row: Record): PilotCustodyIdentity { const identity = { version: Number(row.version), mode: row.mode, policy: row.policy, marketNetwork: row.market_network, marketChainId: row.market_chain_id, moneroNetwork: row.monero_network, custodianId: row.custodian_id, activationStatus: row.activation_status, initializedAt: Number(row.initialized_at), } as PilotCustodyIdentity; if (identity.version !== 1 || identity.mode !== 'pilot-custody' || identity.policy !== 'pilot-custody-v1' || identity.marketNetwork !== 'wikideck-randomx-pilot-1' || identity.marketChainId !== CHAIN_ID || identity.moneroNetwork !== 'mainnet' || !validUuid(identity.custodianId) || identity.activationStatus !== 'identity-only' || !Number.isSafeInteger(identity.initializedAt) || identity.initializedAt < 0) { throw new Error('Stored pilot custody identity is invalid or inconsistent'); } return identity; } async function requireEmptyFinancialDatabase(client: PoolClient, allowPilotIdentity = false): Promise { const result = await client.query(`SELECT NOT wk_custody.pilot_reservation_database_isolated() AS populated, (SELECT count(*) FROM wk_custody.pilot_custody_identity) AS pilot_identities`); if (result.rows[0].populated) { throw new Error('Pilot identity requires a separate empty custody database; existing mock or financial data cannot be reused'); } const identities = Number(result.rows[0].pilot_identities); if ((!allowPilotIdentity && identities !== 0) || (allowPilotIdentity && identities !== 1)) { throw new Error('Pilot custody database identity state is inconsistent'); } if (!allowPilotIdentity) { const reservations = await client.query('SELECT EXISTS(SELECT 1 FROM wk_custody.pilot_monero_deposit_reservations) AS populated'); if (reservations.rows[0].populated) throw new Error('Pilot identity requires an empty pilot reservation table'); } } /** Recheck the dedicated database boundary before each reservation; only its single identity row is allowed. */ export async function assertPilotReservationDatabaseEmpty(client: PoolClient): Promise { await requireEmptyFinancialDatabase(client, true); } /** One-time identity binding only. It does not enable deposit allocation, observation, credit, or withdrawal roles. */ export async function initializePilotCustodyIdentity(pool: Pool, custodianId: string, initializedAt = Date.now()): Promise { requirePilot(custodianId, initializedAt); const expected: PilotCustodyIdentity = { version: 1, mode: 'pilot-custody', policy: 'pilot-custody-v1', marketNetwork: 'wikideck-randomx-pilot-1', marketChainId: CHAIN_ID, moneroNetwork: 'mainnet', custodianId: custodianId.toLowerCase(), activationStatus: 'identity-only', initializedAt }; const client = await pool.connect(); try { await client.query('BEGIN'); await client.query("SET LOCAL statement_timeout='10s'; SET LOCAL lock_timeout='3s'; SET LOCAL synchronous_commit=on"); await client.query('SELECT pg_advisory_xact_lock($1::bigint)', [CUSTODY_WRITE_LOCK]); await verifyCustodySchema(client); const current = await client.query('SELECT * FROM wk_custody.pilot_custody_identity WHERE singleton=1 FOR UPDATE'); if (current.rowCount) { const identity = pilotCustodyIdentityFromRow(current.rows[0]); if (identity.version !== expected.version || identity.mode !== expected.mode || identity.policy !== expected.policy || identity.marketNetwork !== expected.marketNetwork || identity.marketChainId !== expected.marketChainId || identity.moneroNetwork !== expected.moneroNetwork || identity.custodianId !== expected.custodianId) { throw new Error('Pilot custody database is already bound to a different market, Monero network, or custodian'); } await client.query('COMMIT'); return identity; } await requireEmptyFinancialDatabase(client); await client.query(`INSERT INTO wk_custody.pilot_custody_identity (singleton,version,mode,policy,market_network,market_chain_id,monero_network,custodian_id,activation_status,initialized_at) VALUES(1,$1,$2,$3,$4,$5,$6,$7,$8,$9)`, [expected.version, expected.mode, expected.policy, expected.marketNetwork, expected.marketChainId, expected.moneroNetwork, expected.custodianId, expected.activationStatus, expected.initializedAt]); await client.query('COMMIT'); return expected; } catch (error) { await client.query('ROLLBACK').catch(() => {}); throw error; } finally { client.release(); } } export async function verifyPilotCustodyIdentity(pool: Pool, custodianId: string): Promise { requirePilot(custodianId, 0); const result = await pool.query('SELECT * FROM wk_custody.pilot_custody_identity WHERE singleton=1'); if (result.rowCount !== 1) throw new Error('Pilot custody identity is not initialized'); const identity = pilotCustodyIdentityFromRow(result.rows[0]); if (identity.custodianId !== custodianId.toLowerCase()) throw new Error('Pilot custody identity does not match configured custodian'); return identity; } export function parsePilotCustodianId(value: string): string { if (!validUuid(value)) throw new Error('Invalid pilot custodian UUID'); return value.toLowerCase(); }