packages feed

btc-lsp-0.1.0.0: src/BtcLsp/Yesod/Handler/SwapIntoLnSelect.hs

{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}

module BtcLsp.Yesod.Handler.SwapIntoLnSelect
  ( getSwapIntoLnSelectR,
  )
where

import BtcLsp.Data.Type
import qualified BtcLsp.Math.Swap as Math
import BtcLsp.Storage.Model
import qualified BtcLsp.Storage.Model.SwapIntoLn as SwapIntoLn
import BtcLsp.Yesod.Data.Widget
import qualified BtcLsp.Yesod.Handler.SwapUpdates as SU
import BtcLsp.Yesod.Import
import qualified Data.UUID as UUID

getSwapIntoLnSelectR :: Uuid 'SwapIntoLnTable -> Handler Html
getSwapIntoLnSelectR uuid = do
  app@App {appMRunner = UnliftIO run} <- getYesod
  nodeUri <- liftIO $ run getLndNodeUri
  nodeUriHex <-
    eitherM
      (const badMethod)
      (pure . from @NodeUriHex @Text)
      . pure
      $ tryFrom nodeUri
  nodeUriQr <-
    maybeM badMethod pure
      . pure
      $ toQr nodeUriHex
  swapHash <- maybeM notFound pure (SU.getSwapUpdate app uuid)
  maybeM
    notFound
    ( \swapInfo@SwapIntoLn.SwapInfo {..} -> do
        minAmt <- liftIO $ run getSwapIntoLnMinAmt
        let SwapIntoLn {..} = entityVal swapInfoSwap
        let (msgShort, msgLong, color) =
              case swapIntoLnStatus of
                SwapWaitingFundChain ->
                  ( MsgSwapIntoLnWaitingFundChainShort,
                    MsgSwapIntoLnWaitingFundChainLong
                      minAmt
                      Math.swapLnMaxAmt,
                    Info
                  )
                SwapWaitingPeer ->
                  ( MsgSwapIntoLnFundedShort,
                    MsgSwapIntoLnFundedLong,
                    Info
                  )
                SwapWaitingChan ->
                  ( MsgSwapIntoLnWaitingChanShort,
                    MsgSwapIntoLnWaitingChanLong,
                    Info
                  )
                SwapSucceeded ->
                  ( MsgSwapIntoLnSucceededShort,
                    MsgSwapIntoLnSucceededLong,
                    Success
                  )
                SwapExpired ->
                  ( MsgSwapIntoLnExpiredShort,
                    MsgSwapIntoLnExpiredLong,
                    Danger
                  )
        fundAddrQr <-
          maybeM badMethod pure
            . pure
            . toQr
            $ from swapIntoLnFundAddress
        let mSwapWidget = newSwapWidget swapInfo
        let mUtxoWidget = newUtxoWidget swapInfoUtxo
        let mChanWidget = newChanWidget swapInfoChan
        panelLayout color msgShort msgLong $ do
          setTitleI $ MsgSwapIntoLnSelectRTitle swapIntoLnUuid
          $(widgetFile "swap_updates")
          $(widgetFile "swap_into_ln_select")
    )
    . liftIO
    . run
    . runSql
    $ SwapIntoLn.getByUuidSql uuid
  where
    htmlUuid = $(mkHtmlUuid)

newSwapWidget ::
  SwapIntoLn.SwapInfo ->
  Maybe Widget
newSwapWidget swapInfo =
  newNamedListWidget MsgSwapIntoLnHeaderInfo
    . singleton
    $ [ ( MsgSwapIntoLnTotalOnChainReceived,
          Just
            . MsgSatoshi
            $ totalOnChainAmt (/= SwapUtxoOrphan) swapInfo
        ),
        ( MsgSwapIntoLnTotalOnChainReserved,
          Just
            . MsgSatoshi
            $ totalOnChainAmt
              ( `elem`
                  [ SwapUtxoUnspentChanReserve
                  ]
              )
              swapInfo
        ),
        ( MsgSwapIntoLnTotalOnChainSwapped,
          Just
            . MsgSatoshi
            $ totalOnChainAmt
              (== SwapUtxoSpentChanSwapped)
              swapInfo
        ),
        ( MsgSwapIntoLnTotalOnChainRefunded,
          Just
            . MsgSatoshi
            $ totalOnChainAmt (== SwapUtxoSpentRefund) swapInfo
        ),
        ( MsgSwapIntoLnTotalOnChainDust,
          Just
            . MsgSatoshi
            $ totalOnChainAmt (== SwapUtxoUnspentDust) swapInfo
        ),
        ( MsgSwapIntoLnFeeLsp,
          Just
            . MsgSatoshi
            $ from swapIntoLnFeeLsp
        ),
        ( MsgSwapIntoLnChanCapUser,
          Just
            . MsgSatoshi
            $ from swapIntoLnChanCapUser
        ),
        ( MsgSwapIntoLnChanCapLsp,
          Just
            . MsgSatoshi
            $ from swapIntoLnChanCapLsp
        ),
        ( MsgSwapIntoLnChanCapTotal,
          Just
            . MsgSatoshi
            $ from swapIntoLnChanCapUser
              + from swapIntoLnChanCapLsp
        ),
        ( MsgChannelPrivacy,
          Just $
            chanPrivacyMsg swapIntoLnPrivacy
        ),
        ( MsgStatus,
          Just $
            swapStatusMsg swapIntoLnStatus
        ),
        ( MsgExpiresAt,
          Just $
            MsgUtcTime swapIntoLnExpiresAt
        ),
        ( MsgSwapIntoLnUuid,
          Just
            . MsgProxy
            . UUID.toText
            . unUuid
            $ swapIntoLnUuid
        ),
        ( MsgSwapIntoLnUserId,
          Just $
            MsgProxy userPub
        ),
        ( MsgSwapIntoLnFundAddress,
          Just
            . MsgProxy
            $ toText swapIntoLnFundAddress
        ),
        ( MsgSwapIntoLnRefundAddress,
          Just
            . MsgProxy
            $ toText swapIntoLnRefundAddress
        ),
        ( MsgInsertedAt,
          Just $
            MsgUtcTime swapIntoLnInsertedAt
        ),
        ( MsgUpdatedAt,
          Just $
            MsgUtcTime swapIntoLnUpdatedAt
        )
      ]
      >>= \case
        (msg, Just txt) -> [(msg, txt)]
        (_, Nothing) -> []
  where
    SwapIntoLn {..} =
      entityVal $
        SwapIntoLn.swapInfoSwap swapInfo
    userPub =
      toHex
        . coerce
        . userNodePubKey
        . entityVal
        $ SwapIntoLn.swapInfoUser swapInfo

totalOnChainAmt ::
  (SwapUtxoStatus -> Bool) ->
  SwapIntoLn.SwapInfo ->
  MSat
totalOnChainAmt only =
  from
    . sum
    . fmap swapUtxoAmount
    . filter (only . swapUtxoStatus)
    . fmap (entityVal . SwapIntoLn.utxoInfoUtxo)
    . SwapIntoLn.swapInfoUtxo

newUtxoWidget :: [SwapIntoLn.UtxoInfo] -> Maybe Widget
newUtxoWidget utxos =
  newNamedListWidget MsgSwapIntoLnHeaderUtxos $
    ( \row ->
        let SwapUtxo {..} =
              entityVal $ SwapIntoLn.utxoInfoUtxo row
            Block {..} =
              entityVal $ SwapIntoLn.utxoInfoBlock row
         in [ ( MsgBlock,
                MsgProxy
                  . inspectPlain @Word64
                  $ from blockHeight
              ),
              ( MsgAmount,
                MsgSatoshi $
                  from swapUtxoAmount
              ),
              ( MsgStatus,
                swapUtxoStatusMsg swapUtxoStatus
              ),
              ( MsgTxId,
                MsgProxy
                  . txIdHex
                  $ coerce swapUtxoTxid
              ),
              ( MsgVout,
                MsgProxy
                  . inspectPlain @Word32
                  $ coerce swapUtxoVout
              ),
              ( MsgInsertedAt,
                MsgUtcTime swapUtxoInsertedAt
              ),
              ( MsgUpdatedAt,
                MsgUtcTime swapUtxoUpdatedAt
              )
            ]
    )
      <$> utxos

newChanWidget :: [Entity LnChan] -> Maybe Widget
newChanWidget chans =
  newNamedListWidget MsgSwapIntoLnHeaderChans $
    ( \row ->
        let LnChan {..} = entityVal row
         in [ ( MsgStatus,
                lnChanStatusMsg lnChanStatus
              ),
              ( MsgTxId,
                MsgProxy
                  . txIdHex
                  $ coerce lnChanFundingTxId
              ),
              ( MsgVout,
                MsgProxy
                  . inspectPlain @Word32
                  $ coerce lnChanFundingVout
              ),
              ( MsgInsertedAt,
                MsgUtcTime lnChanInsertedAt
              ),
              ( MsgUpdatedAt,
                MsgUtcTime lnChanUpdatedAt
              )
            ]
    )
      <$> chans

swapStatusMsg :: SwapStatus -> AppMessage
swapStatusMsg = \case
  SwapWaitingFundChain -> MsgSwapWaitingFundChain
  SwapWaitingPeer -> MsgSwapWaitingPeer
  SwapWaitingChan -> MsgSwapWaitingChan
  SwapSucceeded -> MsgSwapSucceeded
  SwapExpired -> MsgSwapExpired

chanPrivacyMsg :: Privacy -> AppMessage
chanPrivacyMsg = \case
  Private -> MsgChanPrivate
  Public -> MsgChanPublic

swapUtxoStatusMsg :: SwapUtxoStatus -> AppMessage
swapUtxoStatusMsg = \case
  SwapUtxoUnspent -> MsgSwapUtxoUnspent
  SwapUtxoUnspentDust -> MsgSwapUtxoUnspentDust
  SwapUtxoUnspentChanReserve -> MsgSwapUtxoUnspentChanReserve
  SwapUtxoSpentChanSwapped -> MsgSwapUtxoSpentChanSwapped
  SwapUtxoSpentRefund -> MsgSwapUtxoSpentRefund
  SwapUtxoOrphan -> MsgSwapUtxoOrphan

lnChanStatusMsg :: LnChanStatus -> AppMessage
lnChanStatusMsg = \case
  LnChanStatusPendingOpen -> MsgLnChanStatusPendingOpen
  LnChanStatusOpened -> MsgLnChanStatusOpened
  LnChanStatusActive -> MsgLnChanStatusActive
  LnChanStatusFullyResolved -> MsgLnChanStatusFullyResolved
  LnChanStatusInactive -> MsgLnChanStatusInactive
  LnChanStatusPendingClose -> MsgLnChanStatusPendingClose
  LnChanStatusClosed -> MsgLnChanStatusClosed