synapsecns/sanguine

View on GitHub
packages/synapse-interface/utils/slippage.ts

Summary

Maintainability
C
1 day
Test Coverage
import { BigNumber } from '@ethersproject/bignumber'
import { formatUnits } from '@ethersproject/units'

export const Slippages = {
  One: 'ONE',
  OneTenth: 'ONE_TENTH',
  TwoTenth: 'TWO_TENTH',
  Quarter: 'QUARTER',
  OnePercent: 'ONE_PERCENT',
  Custom: 'CUSTOM',
  OneHundredth: 'ONE_HUNDREDTH',
}

/**
 * Given an input value and slippage redux state values, do the math.
 *
 * @param {BigNumber} inputValue
 * @param {Slippages} slippageSelected
 * @param {NumberInputState} slippageCustom
 * @param {boolean} add
 * @return {BigNumber}
 */
export const _applySlippage = (
  inputValue,
  slippageSelected,
  slippageCustom,
  add = false
) => {
  let numerator
  let denominator
  if (slippageSelected === Slippages.Custom && !!slippageCustom) {
    denominator = BigNumber.from(10).pow(slippageCustom.precision + 2)
    numerator = add
      ? denominator.add(slippageCustom.valueSafe)
      : denominator.sub(slippageCustom.valueSafe)
  } else if (slippageSelected === Slippages.OneTenth) {
    denominator = 1000
    numerator = denominator + (add ? 1 : -1)
  } else if (slippageSelected === Slippages.OneHundredth) {
    denominator = 10000
    numerator = denominator + (add ? 1 : -1)
  } else if (slippageSelected === Slippages.TwoTenth) {
    denominator = 500
    numerator = denominator + (add ? 1 : -1)
  } else if (slippageSelected === Slippages.Quarter) {
    denominator = 50
    numerator = denominator + (add ? 1 : -1)
  } else if (slippageSelected === Slippages.OnePercent) {
    denominator = 100
    numerator = denominator + (add ? 1 : -1)
  } else {
    // default to 1%
    denominator = 100
    numerator = denominator + (add ? 1 : -1)
  }
  return inputValue.mul(numerator).div(denominator)
}

export const addSlippage = (inputValue, slippageSelected, slippageCustom) => {
  return _applySlippage(inputValue, slippageSelected, slippageCustom, true)
}

export const subtractSlippage = (
  inputValue,
  slippageSelected,
  slippageCustom
) => {
  return _applySlippage(inputValue, slippageSelected, slippageCustom, false)
}

export const formatSlippageToString = (slippageSelected, slippageCustom) => {
  if (slippageSelected === Slippages.Custom && !!slippageCustom) {
    return formatUnits(slippageCustom.valueSafe, slippageCustom?.precision)
  } else if (slippageSelected === Slippages.OneTenth) {
    return formatUnits(BigNumber.from(100), 3)
  } else if (slippageSelected === Slippages.TwoTenth) {
    return formatUnits(BigNumber.from(200), 3)
  } else if (slippageSelected === Slippages.Quarter) {
    return formatUnits(BigNumber.from(2000), 3)
  } else if (slippageSelected === Slippages.One) {
    return formatUnits(BigNumber.from(100), 2)
  } else {
    return 'N/A'
  }
}

// Below functions are dupes of above functions except with input and output values of bigint
// When app completely removes need for BigNumber, we can deprecate the BigNumber versions

// TODO Unit test below

/**
 * Given an input value and slippage redux state values, do the math.
 *
 * @param {bigint} inputValue
 * @param {Slippages} slippageSelected
 * @param {NumberInputState} slippageCustom
 * @param {boolean} add
 * @return {bigint}
 */
export const _applySlippageBigInt = (
  inputValue,
  slippageSelected,
  slippageCustom,
  add = false
) => {
  let numerator
  let denominator
  if (slippageSelected === Slippages.Custom && !!slippageCustom) {
    denominator = 10n ** BigInt(slippageCustom.precision + 2)
    numerator = add
      ? denominator + slippageCustom.valueSafe
      : denominator - slippageCustom.valueSafe
  } else if (slippageSelected === Slippages.OneTenth) {
    denominator = 1000n
    numerator = add ? denominator + 1n : denominator - 1n
  } else if (slippageSelected === Slippages.OneHundredth) {
    denominator = 10000n
    numerator = add ? denominator + 1n : denominator - 1n
  } else if (slippageSelected === Slippages.TwoTenth) {
    denominator = 500n
    numerator = add ? denominator + 1n : denominator - 1n
  } else if (slippageSelected === Slippages.Quarter) {
    denominator = 400n
    numerator = add ? denominator + 1n : denominator - 1n
  } else if (slippageSelected === Slippages.OnePercent) {
    denominator = 100n
    numerator = add ? denominator + 1n : denominator - 1n
  } else {
    // default to 1%
    denominator = 100n
    numerator = add ? denominator + 1n : denominator - 1n
  }
  return (inputValue * numerator) / denominator
}

export const subtractSlippageBigInt = (
  inputValue,
  slippageSelected,
  slippageCustom
) => {
  return _applySlippageBigInt(
    inputValue,
    slippageSelected,
    slippageCustom,
    false
  )
}