/** * Per-skill bonding curve — demand/supply pricing for intent marketplace. * * Formula: price = BASE_SKILL_PRICE × (demandHours / supplyHours) ^ ELASTICITY * * High demand + low supply → higher price → incentivizes offers. * All prices in tokens per hour. */ import type { Skill } from './schemas'; import type { SkillCurvesDoc, SkillCurveEntry } from './schemas-intent'; // ── Curve parameters ── /** Base price in tokens per hour */ export const BASE_SKILL_PRICE = 100; /** Elasticity exponent — 0.5 = square root (moderate responsiveness) */ export const ELASTICITY = 0.5; /** Minimum supply to avoid division by zero / extreme prices */ const MIN_SUPPLY = 1; /** Maximum price cap (10x base) to prevent runaway pricing */ const MAX_PRICE = BASE_SKILL_PRICE * 10; // ── Price functions ── /** * Calculate the current price per hour for a skill. * Returns tokens per hour. */ export function getSkillPrice(skill: Skill, curves: SkillCurvesDoc): number { const curve = curves.curves[skill]; if (!curve || curve.supplyHours <= 0) return BASE_SKILL_PRICE; const supply = Math.max(curve.supplyHours, MIN_SUPPLY); const demand = Math.max(curve.demandHours, 0); const ratio = demand / supply; const price = Math.round(BASE_SKILL_PRICE * Math.pow(ratio, ELASTICITY)); return Math.min(price, MAX_PRICE); } /** * Calculate the total cost for a need intent (hours × skill price). */ export function calculateIntentCost(skill: Skill, hours: number, curves: SkillCurvesDoc): number { const price = getSkillPrice(skill, curves); return price * hours; } /** * Get all current skill prices. */ export function getAllSkillPrices(curves: SkillCurvesDoc): Record { const skills: Skill[] = ['facilitation', 'design', 'tech', 'outreach', 'logistics']; const prices = {} as Record; for (const skill of skills) { prices[skill] = getSkillPrice(skill, curves); } return prices; } /** * Create or update a skill curve entry after an intent is created/withdrawn. * Returns the updated curve entry. */ export function recalculateCurve( skill: Skill, supplyHours: number, demandHours: number, ): Omit { const supply = Math.max(supplyHours, MIN_SUPPLY); const demand = Math.max(demandHours, 0); const ratio = demand / supply; const price = Math.min(Math.round(BASE_SKILL_PRICE * Math.pow(ratio, ELASTICITY)), MAX_PRICE); return { skill, supplyHours, demandHours, currentPrice: price, }; } /** * Get curve configuration for UI display. */ export function getSkillCurveConfig() { return { basePrice: BASE_SKILL_PRICE, elasticity: ELASTICITY, maxPrice: MAX_PRICE, }; }