UNPKG

@cobaltx/sdk-v2

Version:

An SDK for building applications on top of CobaltX.

81 lines (61 loc) 2.6 kB
import BN from "bn.js"; import { RoundDirection, SwapWithoutFeesResult, TradingTokenResult } from "./calculator"; function checkedRem(dividend: BN, divisor: BN): BN { if (divisor.isZero()) throw Error("divisor is zero"); const result = dividend.mod(divisor); return result; } function checkedCeilDiv(dividend: BN, rhs: BN): BN[] { if (rhs.isZero()) throw Error("rhs is zero"); let quotient = dividend.div(rhs); if (quotient.isZero()) throw Error("quotient is zero"); let remainder = checkedRem(dividend, rhs); if (remainder.gt(ZERO)) { quotient = quotient.add(new BN(1)); rhs = dividend.div(quotient); remainder = checkedRem(dividend, quotient); if (remainder.gt(ZERO)) { rhs = rhs.add(new BN(1)); } } return [quotient, rhs]; } const ZERO = new BN(0); export class ConstantProductCurve { static swapWithoutFees(sourceAmount: BN, swapSourceAmount: BN, swapDestinationAmount: BN): SwapWithoutFeesResult { const invariant = swapSourceAmount.mul(swapDestinationAmount); const newSwapSourceAmount = swapSourceAmount.add(sourceAmount); const [newSwapDestinationAmount, _newSwapSourceAmount] = checkedCeilDiv(invariant, newSwapSourceAmount); const sourceAmountSwapped = _newSwapSourceAmount.sub(swapSourceAmount); const destinationAmountSwapped = swapDestinationAmount.sub(newSwapDestinationAmount); if (destinationAmountSwapped.isZero()) throw Error("destinationAmountSwapped is zero"); return { sourceAmountSwapped, destinationAmountSwapped, }; } static lpTokensToTradingTokens( lpTokenAmount: BN, lpTokenSupply: BN, swapTokenAmount0: BN, swapTokenAmount1: BN, roundDirection: RoundDirection, ): TradingTokenResult { let tokenAmount0 = lpTokenAmount.mul(swapTokenAmount0).div(lpTokenSupply); let tokenAmount1 = lpTokenAmount.mul(swapTokenAmount1).div(lpTokenSupply); if (roundDirection === RoundDirection.Floor) { return { tokenAmount0, tokenAmount1 }; } else if (roundDirection === RoundDirection.Ceiling) { const tokenRemainder0 = checkedRem(lpTokenAmount.mul(swapTokenAmount0), lpTokenSupply); if (tokenRemainder0.gt(ZERO) && tokenAmount0.gt(ZERO)) { tokenAmount0 = tokenAmount0.add(new BN(1)); } const token1Remainder = checkedRem(lpTokenAmount.mul(swapTokenAmount1), lpTokenSupply); if (token1Remainder.gt(ZERO) && tokenAmount1.gt(ZERO)) { tokenAmount1 = tokenAmount1.add(new BN(1)); } return { tokenAmount0, tokenAmount1 }; } throw Error("roundDirection value error"); } }