// Digital Beneficial Claims data model. // Originally built ahead of Horizon 2 PRD's stated gate: "No engineering work begins // until Phase 0 (legal opinion + signed institutional partner agreement) is // complete." Phase 0 is now RESOLVED — both are signed, clearing the way to build // the real legal wrapper (SPV/trust, Horizon 2 PRD §5.1) and institutional // integration. Neither has been built yet, so this module still ships as a local, // non-custodial demonstration only, structurally enforcing the PRD §5.2 transfer // restriction (no open market). Nothing here moves real assets or represents a real // legal claim until that integration work lands. import { load, save } from '../storage.js'; const KEY = 'h2Claims'; /** * @param {object} params { assetId, assetLabel, heirPoolId, holderName, heirShareFraction, faraidRulingRef } */ export function issueClaim(params) { const claims = load(KEY, []); const claim = { id: crypto.randomUUID(), status: 'issued', // issued | transferred | bought-back issuedAt: new Date().toISOString(), history: [{ event: 'issued', at: new Date().toISOString(), to: params.holderName }], ...params }; claims.push(claim); save(KEY, claims); return claim; } export function listClaims() { return load(KEY, []); } /** * Transfer restriction per Horizon 2 PRD §5.2: a claim may only transfer to * (a) another verified heir within the same heir pool for that asset, or * (b) the legal wrapper entity itself (buy-back). No default path to an open market — * structurally enforced here, not left to UI copy alone. */ export function transferClaim(claimId, { toHolderName, toHeirPoolId, mode }) { const claims = load(KEY, []); const claim = claims.find(c => c.id === claimId); if (!claim) throw new Error('Claim not found'); if (mode === 'buy-back') { claim.status = 'bought-back'; claim.history.push({ event: 'buy-back', at: new Date().toISOString(), note: 'valuation set by independent valuation, not a market bid (demo: no real valuation engine wired)' }); } else if (mode === 'heir-pool-transfer') { if (toHeirPoolId !== claim.heirPoolId) { throw new Error('BLOCKED: recipient is not in the same faraid-determined heir pool for this asset. Per PRD §5.2 there is no default path to an open market.'); } claim.holderName = toHolderName; claim.status = 'transferred'; claim.history.push({ event: 'transfer', at: new Date().toISOString(), to: toHolderName }); } else { throw new Error('Unsupported transfer mode — pre-approved licensed institutional buyer flow requires a separately reviewed compliance process not modelled here.'); } save(KEY, claims); return claim; } export function removeClaim(claimId) { const claims = load(KEY, []).filter(c => c.id !== claimId); save(KEY, claims); }