98 lines
3.0 KiB
TypeScript
98 lines
3.0 KiB
TypeScript
/**
|
||
* 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,
|
||
};
|
||
}
|