/** * CRDT-native bonding curve — pure math functions for $MYCO ↔ cUSDC swaps. * * Polynomial curve: price = basePrice + coefficient × supply² * Ported from payment-infra/services/bonding-curve-service for CRDT ledger integration. * * All amounts in base units: * - cUSDC: 6 decimals (1_000_000 = $1.00) * - $MYCO: 6 decimals (using 6 effective decimals same as cUSDC for simplicity) */ // ── Curve parameters ── /** Base price in cUSDC units (6 decimals) — $0.01 */ const BASE_PRICE = 10_000; /** Coefficient — controls curve steepness */ const COEFFICIENT = 0.000001; /** Exponent — quadratic curve */ const EXPONENT = 2; /** Sell fee in basis points (0.5% = 50 bps) */ const SELL_FEE_BPS = 50; // ── Price functions ── /** Calculate token price at a given supply (both in base units). Returns cUSDC base units per MYCO. */ export function calculatePrice(supplyBaseUnits: number): number { const supplyTokens = supplyBaseUnits / 1_000_000; return Math.round(BASE_PRICE + COEFFICIENT * Math.pow(supplyTokens, EXPONENT) * 1_000_000); } /** Calculate tokens received for cUSDC input (buy). */ export function calculateBuyReturn(cUSDCAmount: number, currentSupply: number): { tokensOut: number; averagePrice: number; priceImpact: number; endPrice: number; } { const startPrice = calculatePrice(currentSupply); // First estimate with start price const estimatedTokens = Math.floor((cUSDCAmount * 1_000_000) / startPrice); const endPrice = calculatePrice(currentSupply + estimatedTokens); const averagePrice = Math.round((startPrice + endPrice) / 2); // Recalculate with average price const tokensOut = Math.floor((cUSDCAmount * 1_000_000) / averagePrice); // Price impact as percentage (0-100) const priceImpact = startPrice > 0 ? Number(((endPrice - startPrice) / startPrice * 100).toFixed(2)) : 0; return { tokensOut, averagePrice, priceImpact, endPrice }; } /** Calculate cUSDC received for $MYCO input (sell), after fee. */ export function calculateSellReturn(mycoAmount: number, currentSupply: number): { cUSDCOut: number; grossAmount: number; fee: number; averagePrice: number; priceImpact: number; endPrice: number; } { if (mycoAmount > currentSupply) { throw new Error('Cannot sell more than current supply'); } const startPrice = calculatePrice(currentSupply); const endPrice = calculatePrice(currentSupply - mycoAmount); const averagePrice = Math.round((startPrice + endPrice) / 2); const grossAmount = Math.floor((mycoAmount * averagePrice) / 1_000_000); const fee = Math.floor((grossAmount * SELL_FEE_BPS) / 10_000); const cUSDCOut = grossAmount - fee; const priceImpact = startPrice > 0 ? Number(((startPrice - endPrice) / startPrice * 100).toFixed(2)) : 0; return { cUSDCOut, grossAmount, fee, averagePrice, priceImpact, endPrice }; } /** Get current curve configuration (for UI display). */ export function getCurveConfig() { return { basePrice: BASE_PRICE, coefficient: COEFFICIENT, exponent: EXPONENT, sellFeeBps: SELL_FEE_BPS, priceDecimals: 6, tokenDecimals: 6, }; }