packages feed

btc-lsp-0.1.0.0: src/BtcLsp/Math/Swap.hs

{-# LANGUAGE TypeApplications #-}

module BtcLsp.Math.Swap
  ( SwapCap (..),
    swapExpiryLimitInput,
    swapExpiryLimitInternal,
    swapLnMaxAmt,
    swapLnFeeRate,
    swapLnMinFee,
    newSwapCapM,
    newSwapIntoLnMinAmt,
  )
where

import BtcLsp.Class.Env
import BtcLsp.Data.Kind
import BtcLsp.Data.Type
import BtcLsp.Import.External
import qualified LndClient as Lnd

data SwapCap = SwapCap
  { swapCapUsr :: Money 'Usr 'Ln 'Fund,
    swapCapLsp :: Money 'Lsp 'Ln 'Fund,
    swapCapFee :: Money 'Lsp 'OnChain 'Gain
  }
  deriving stock
    ( Eq,
      Ord,
      Show,
      Generic
    )

instance Out SwapCap

swapExpiryLimitInput :: Lnd.Seconds
swapExpiryLimitInput =
  Lnd.Seconds $ (7 * 24 - 1) * 3600

swapExpiryLimitInternal :: Lnd.Seconds
swapExpiryLimitInternal =
  Lnd.Seconds 3600

swapLnMaxAmt :: Money 'Usr btcl 'Fund
swapLnMaxAmt =
  Money $ MSat 10000000000

swapLnFeeRate :: FeeRate
swapLnFeeRate =
  FeeRate 0.004

swapLnMinFee :: Money 'Lsp btcl 'Gain
swapLnMinFee =
  Money $ MSat 2000000

newSwapCapM ::
  ( Env m
  ) =>
  Money 'Usr 'OnChain 'Fund ->
  m (Maybe SwapCap)
newSwapCapM usrAmt = do
  minAmt <- getSwapIntoLnMinAmt
  pure $
    if usrAmt < minAmt
      then Nothing
      else
        Just
          SwapCap
            { swapCapUsr = usrLn,
              swapCapLsp = coerce usrLn,
              swapCapFee = from @Word64 $ ceiling feeRat
            }
  where
    usrFin :: Ratio Word64
    usrFin =
      from usrAmt % 1
    feeRat :: Ratio Word64
    feeRat =
      from @Word64
        . (* 1000)
        . ceiling
        . (/ 1000)
        . max (from swapLnMinFee % 1)
        $ usrFin * from swapLnFeeRate
    usrLn :: Money 'Usr 'Ln 'Fund
    usrLn =
      from @Word64
        . floor
        $ usrFin - feeRat

newSwapIntoLnMinAmt ::
  Money 'Chan 'Ln 'Fund ->
  Money 'Usr 'OnChain 'Fund
newSwapIntoLnMinAmt minCap =
  from @Word64
    . (* 1000)
    . ceiling
    $ usrInitMsat / 1000
  where
    minFee :: Ratio Word64
    minFee =
      from swapLnMinFee % 1
    usrFin :: Ratio Word64
    usrFin =
      from minCap % 2
    usrPerc :: Ratio Word64
    usrPerc =
      usrFin / (1 - from swapLnFeeRate)
    usrInitMsat :: Ratio Word64
    usrInitMsat =
      if usrPerc - usrFin >= minFee
        then usrPerc
        else usrFin + minFee