packages feed

btc-lsp-0.1.0.0: test/ServerSpec.hs

{-# LANGUAGE TypeApplications #-}

module ServerSpec
  ( spec,
  )
where

import qualified BtcLsp.Grpc.Client.HighLevel as Client
import BtcLsp.Grpc.Client.LowLevel
import BtcLsp.Grpc.Orphan ()
import BtcLsp.Import hiding (setGrpcCtx, setGrpcCtxT)
import qualified BtcLsp.Storage.Model.LnChan as L
import qualified BtcLsp.Storage.Model.SwapIntoLn as S
import qualified BtcLsp.Storage.Model.SwapUtxo as SU
import qualified LndClient as Lnd
import qualified LndClient.Data.Channel as Lnd
import qualified LndClient.Data.ListChannels as ListChannels
import LndClient.LndTest (lazyConnectNodes, mine)
import qualified LndClient.RPC.Silent as Lnd
import qualified Network.Bitcoin as Btc
import qualified Proto.BtcLsp.Data.HighLevel as Proto
import qualified Proto.BtcLsp.Data.HighLevel_Fields as Proto
import qualified Proto.BtcLsp.Data.LowLevel_Fields as LowLevel
import qualified Proto.BtcLsp.Data.LowLevel_Fields as SwapIntoLn
import qualified Proto.BtcLsp.Method.GetCfg_Fields as GetCfg
import qualified Proto.BtcLsp.Method.SwapIntoLn_Fields as SwapIntoLn
import Test.Hspec
import TestAppM
import TestHelpers
import TestOrphan ()

getChannels :: Env m => Lnd.NodePubKey -> ExceptT Failure m [Lnd.Channel]
getChannels pub =
  withLndT
    Lnd.listChannels
    ( $
        ListChannels.ListChannelsRequest
          { ListChannels.activeOnly = True,
            ListChannels.inactiveOnly = False,
            ListChannels.publicOnly = False,
            ListChannels.privateOnly = False,
            ListChannels.peer = Just pub
          }
    )

spec :: Spec
spec = forM_ [Compressed, Uncompressed] $ \compressMode -> do
  itMainT @'LndLsp "GetCfg" $ do
    let minAmt :: Proto.LocalBalance =
          defMessage
            & Proto.val
              .~ ( defMessage
                     & LowLevel.val .~ 12000000
                 )
    let maxAmt :: Proto.LocalBalance =
          defMessage
            & Proto.val
              .~ ( defMessage
                     & LowLevel.val .~ 10000000000
                 )
    gcEnv <- lift getGCEnv
    pub <- getPubKeyT LndLsp
    res0 <-
      Client.getCfgT
        gcEnv
          { gcEnvCompressMode = compressMode
          }
        =<< setGrpcCtxT LndAlice defMessage
    liftIO $
      (res0 ^. GetCfg.success)
        `shouldBe` ( defMessage
                       & GetCfg.lspLnNodes
                         .~ [ defMessage
                                & Proto.pubKey
                                  .~ from pub
                                & Proto.host
                                  .~ ( defMessage
                                         & Proto.val .~ "127.0.0.1"
                                     )
                                & Proto.port
                                  .~ ( defMessage
                                         & Proto.val .~ 9736
                                     )
                            ]
                       & GetCfg.swapIntoLnMinAmt .~ minAmt
                       & GetCfg.swapIntoLnMaxAmt .~ maxAmt
                       & GetCfg.swapFromLnMinAmt .~ minAmt
                       & GetCfg.swapFromLnMaxAmt .~ maxAmt
                       & GetCfg.swapLnFeeRate
                         .~ ( defMessage
                                & Proto.val
                                  .~ ( defMessage
                                         & LowLevel.numerator .~ 1
                                         & LowLevel.denominator .~ 250
                                     )
                            )
                       & GetCfg.swapLnMinFee
                         .~ ( defMessage
                                & Proto.val
                                  .~ ( defMessage
                                         & LowLevel.val .~ 2000000
                                     )
                            )
                   )
  itMainT @'LndLsp "Server SwapIntoLn" $ do
    gcEnv <- lift getGCEnv
    refundAddr <- from <$> genAddress LndAlice
    res0 <-
      Client.swapIntoLnT
        gcEnv
          { gcEnvCompressMode = compressMode
          }
        =<< setGrpcCtxT
          LndAlice
          ( defMessage
              & SwapIntoLn.refundOnChainAddress
                .~ from @(OnChainAddress 'Refund) refundAddr
          )

    liftIO $
      res0
        `shouldSatisfy` ( \msg ->
                            isJust $
                              msg ^. SwapIntoLn.maybe'success
                        )
    let fundAddr =
          res0
            ^. ( SwapIntoLn.success
                   . SwapIntoLn.fundOnChainAddress
                   . SwapIntoLn.val
                   . SwapIntoLn.val
               )
    alicePub <- getPubKeyT LndAlice
    void $ withBtcT Btc.sendToAddress (\h -> h fundAddr 0.01 Nothing Nothing)
    lift $ mine 5 LndLsp >> sleep1s >> lazyConnectNodes (Proxy :: Proxy TestOwner)
    checksPassed <-
      lift $
        waitCond
          10
          ( \_ -> do
              mine 5 LndLsp
              eLndChans <- runExceptT $ getChannels alicePub
              mswp <- runSql $ S.getByFundAddressSql (unsafeNewOnChainAddress fundAddr)
              case (mswp, eLndChans) of
                (Just swp, Right lndChans) -> do
                  let swapInDbSuccess = SwapSucceeded == swapIntoLnStatus (entityVal swp)
                  utxos <- runSql $ SU.getUtxosBySwapIdSql $ entityKey swp
                  let allUtxosMarkedAsUsed = all (\u -> swapUtxoStatus (entityVal u) == SwapUtxoSpentChanSwapped) utxos
                  let expectedRemoteBalance = swapIntoLnChanCapUser $ entityVal swp
                  dbChans <- runSql $ L.getBySwapIdSql $ entityKey swp
                  let chanExistInDb = length dbChans == 1
                  let openedChanWithRightCap = isJust $ find (\c -> Lnd.remoteBalance c == from expectedRemoteBalance) lndChans
                  pure (swapInDbSuccess && allUtxosMarkedAsUsed && openedChanWithRightCap && chanExistInDb, ())
                _ -> pure (False, ())
          )
          ()
    liftIO $ do
      shouldBe (fst checksPassed) True