UNPKG

@ocap/util

Version:

utils shared across multiple forge js libs, works in both node.js and browser

151 lines (149 loc) 5.51 kB
import { BN } from "./bn.mjs"; //#region src/curve.ts const ZERO = new BN(0); const TWO = new BN(2); const THREE = new BN(3); const TEN = new BN(10); let Direction = /* @__PURE__ */ function(Direction$1) { Direction$1["Mint"] = "mint"; Direction$1["Burn"] = "burn"; return Direction$1; }({}); /** * Constant Curve * Price = fixedPrice */ function calcConstantPrice({ fixedPrice }) { return new BN(fixedPrice); } /** * Constant Curve * Cost = amount * fixedPrice */ function calcConstantCost({ amount, fixedPrice, decimal }) { const decimalFactor = TEN.pow(new BN(decimal)); return new BN(amount).mul(new BN(fixedPrice)).div(decimalFactor); } /** * linear Curve * Price = basePrice + slope * currentSupply */ function calcLinearPrice({ basePrice, slope, currentSupply, decimal }) { const decimalFactor = TEN.pow(new BN(decimal)); return new BN(basePrice).add(new BN(slope).mul(new BN(currentSupply)).div(decimalFactor)); } /** * Linear Curve * mint Cost = (slope / 2) * ( (currentSupply + amount) ** 2 - currentSupply ** 2 ) + basePrice * amount; * burn Cost = (slope / 2) * ( currentSupply ** 2 - (currentSupply - amount) ** 2 ) + basePrice * amount; */ function calcLinearCost(params) { const amount = new BN(params.amount); const currentSupply = new BN(params.currentSupply); const basePrice = new BN(params.basePrice); const slope = new BN(params.slope); const decimalFactor = TEN.pow(new BN(params.decimal)); if (slope.lte(ZERO)) throw new Error("INVALID_SLOPE"); if (amount.lt(ZERO)) throw new Error("INVALID_AMOUNT"); if (currentSupply.lt(ZERO)) throw new Error("INVALID_CURRENT_SUPPLY"); if (basePrice.lt(ZERO)) throw new Error("INVALID_BASE_PRICE"); if (decimalFactor.lte(ZERO)) throw new Error("INVALID_DECIMAL_FACTOR"); if (params.direction === Direction.Burn && amount.gt(currentSupply)) throw new Error("SUPPLY_INSUFFICIENT"); const integralDelta = params.direction === Direction.Mint ? amount.mul(currentSupply.mul(TWO).add(amount)) : amount.mul(currentSupply.mul(TWO).sub(amount)); const linearTerm = basePrice.mul(amount).div(decimalFactor); const integralTerm = slope.mul(integralDelta).div(TWO.mul(decimalFactor.sqr())); return linearTerm.add(integralTerm); } /** * Quadratic Curve * Price = basePrice + currentSupply ** 2 / constant */ function calcQuadraticPrice(params) { const basePrice = new BN(params.basePrice); const currentSupply = new BN(params.currentSupply); const constant = new BN(params.constant); const decimalFactor = TEN.pow(new BN(params.decimal)); if (constant.lte(ZERO)) throw new Error("INVALID_CONSTANT"); if (currentSupply.lt(ZERO)) throw new Error("INVALID_CURRENT_SUPPLY"); if (basePrice.lt(ZERO)) throw new Error("INVALID_BASE_PRICE"); if (decimalFactor.lte(ZERO)) throw new Error("INVALID_DECIMAL_FACTOR"); const denom = constant.mul(decimalFactor); const a = currentSupply.sqr().div(denom); return basePrice.add(a); } /** * Quadratic Curve * Price = basePrice + currentSupply ** 2 / constant * mint Cost = ( (currentSupply + amount)^3 / 3 - currentSupply^3 / 3 ) / constant + basePrice * amount; * burn Cost = ( currentSupply^3 / 3 - (currentSupply - amount)^3 / 3 ) / constant + basePrice * amount; */ function calcQuadraticCost(params) { const amount = new BN(params.amount); const currentSupply = new BN(params.currentSupply); const basePrice = new BN(params.basePrice); const constant = new BN(params.constant); const decimalFactor = TEN.pow(new BN(params.decimal)); if (constant.lte(ZERO)) throw new Error("INVALID_CONSTANT"); if (amount.lt(ZERO)) throw new Error("INVALID_AMOUNT"); if (amount.isZero()) return ZERO; const newSupply = params.direction === Direction.Mint ? currentSupply.add(amount) : currentSupply.sub(amount); if (params.direction === Direction.Burn && newSupply.lt(ZERO)) throw new Error("SUPPLY_INSUFFICIENT"); const diff = params.direction === Direction.Mint ? newSupply.sub(currentSupply) : currentSupply.sub(newSupply); const sumSquaresAndProduct = newSupply.sqr().add(newSupply.mul(currentSupply)).add(currentSupply.sqr()); const cubicDelta = diff.mul(sumSquaresAndProduct); const denom = THREE.mul(constant).mul(decimalFactor.sqr()); const cubicCost = cubicDelta.div(denom); const linearCost = basePrice.mul(amount).div(decimalFactor); return cubicCost.add(linearCost); } function calcFee({ reserveAmount, feeRate }) { return new BN(reserveAmount).mul(new BN(feeRate)).div(new BN(1e4)); } function calcPrice({ currentSupply, decimal, curve }) { const calculator = { constant: () => calcConstantPrice({ currentSupply, decimal, ...curve }), linear: () => calcLinearPrice({ currentSupply, decimal, ...curve }), quadratic: () => calcQuadraticPrice({ currentSupply, decimal, ...curve }) }[curve.type]; if (!calculator) throw new Error("INVALID_CURVE_TYPE"); return calculator(); } function calcCost({ amount, decimal, currentSupply, direction, curve }) { const calculator = { constant: () => calcConstantCost({ amount, decimal, ...curve }), linear: () => calcLinearCost({ amount, decimal, currentSupply, direction, ...curve }), quadratic: () => calcQuadraticCost({ amount, decimal, currentSupply, direction, ...curve }) }[curve.type]; if (!calculator) throw new Error("INVALID_CURVE_TYPE"); return calculator(); } //#endregion export { Direction, calcConstantCost, calcConstantPrice, calcCost, calcFee, calcLinearCost, calcLinearPrice, calcPrice, calcQuadraticCost, calcQuadraticPrice };