packages feed

btc-lsp-0.1.0.0: src/BtcLsp/Storage/Model/SwapUtxo.hs

module BtcLsp.Storage.Model.SwapUtxo
  ( createIgnoreManySql,
    getSpendableUtxosBySwapIdSql,
    updateUnspentChanReserveSql,
    updateSpentChanSwappedSql,
    updateRefundedSql,
    updateOrphanSql,
    getUtxosForRefundSql,
    getUtxosBySwapIdSql,
    updateRefundBlockIdSql,
    revertRefundedSql,
  )
where

import BtcLsp.Import hiding (Storage (..))
import qualified BtcLsp.Import.Psql as Psql

createIgnoreManySql ::
  ( MonadIO m
  ) =>
  [SwapUtxo] ->
  ReaderT Psql.SqlBackend m ()
createIgnoreManySql us =
  Psql.upsertManyWhere
    us
    [Psql.copyField SwapUtxoUpdatedAt]
    mempty
    mempty

getSpendableUtxosBySwapIdSql ::
  ( MonadIO m
  ) =>
  SwapIntoLnId ->
  ReaderT Psql.SqlBackend m [Entity SwapUtxo]
getSpendableUtxosBySwapIdSql swapId = do
  Psql.select $
    Psql.from $ \row -> do
      Psql.locking Psql.ForUpdate
      Psql.where_
        ( ( row Psql.^. SwapUtxoSwapIntoLnId
              Psql.==. Psql.val swapId
          )
            Psql.&&. ( row Psql.^. SwapUtxoStatus
                         `Psql.in_` Psql.valList
                           [ SwapUtxoUnspent,
                             SwapUtxoUnspentChanReserve
                           ]
                     )
        )
      pure row

updateUnspentChanReserveSql ::
  ( MonadIO m
  ) =>
  [SwapUtxoId] ->
  ReaderT Psql.SqlBackend m RowQty
updateUnspentChanReserveSql ids = do
  ct <- getCurrentTime
  res <- Psql.updateCount $ \row -> do
    Psql.set
      row
      [ SwapUtxoStatus
          Psql.=. Psql.val SwapUtxoUnspentChanReserve,
        SwapUtxoUpdatedAt
          Psql.=. Psql.val ct
      ]
    Psql.where_ $
      ( row Psql.^. SwapUtxoId
          `Psql.in_` Psql.valList ids
      )
        Psql.&&. ( row Psql.^. SwapUtxoStatus
                     `Psql.in_` Psql.valList
                       [ SwapUtxoUnspent,
                         SwapUtxoUnspentChanReserve
                       ]
                 )
  pure $ from res

updateSpentChanSwappedSql ::
  ( MonadIO m
  ) =>
  SwapIntoLnId ->
  ReaderT Psql.SqlBackend m ()
updateSpentChanSwappedSql id0 = do
  ct <- getCurrentTime
  Psql.update $ \row -> do
    Psql.set
      row
      [ SwapUtxoStatus Psql.=. Psql.val SwapUtxoSpentChanSwapped,
        SwapUtxoUpdatedAt Psql.=. Psql.val ct
      ]
    Psql.where_ $
      ( row Psql.^. SwapUtxoSwapIntoLnId
          Psql.==. Psql.val id0
      )
        Psql.&&. ( row Psql.^. SwapUtxoStatus
                     `Psql.in_` Psql.valList
                       [ SwapUtxoUnspentChanReserve
                       ]
                 )

updateRefundedSql ::
  ( MonadIO m
  ) =>
  [SwapUtxoId] ->
  TxId 'Funding ->
  ReaderT Psql.SqlBackend m ()
updateRefundedSql ids rTxId = do
  ct <- getCurrentTime
  Psql.update $ \row -> do
    Psql.set
      row
      [ SwapUtxoStatus Psql.=. Psql.val SwapUtxoSpentRefund,
        SwapUtxoRefundTxId Psql.=. Psql.val (Just rTxId),
        SwapUtxoUpdatedAt Psql.=. Psql.val ct
      ]
    Psql.where_ $
      ( row Psql.^. SwapUtxoId
          `Psql.in_` Psql.valList ids
      )
        Psql.&&. ( row Psql.^. SwapUtxoStatus
                     `Psql.in_` Psql.valList
                       [ SwapUtxoUnspent,
                         SwapUtxoUnspentChanReserve
                       ]
                 )

getUtxosForRefundSql ::
  ( MonadIO m
  ) =>
  ReaderT
    Psql.SqlBackend
    m
    [(Entity SwapUtxo, Entity SwapIntoLn)]
getUtxosForRefundSql =
  Psql.select $
    Psql.from $ \(swap `Psql.InnerJoin` utxo) -> do
      Psql.locking Psql.ForUpdate
      Psql.on
        ( (swap Psql.^. SwapIntoLnId)
            Psql.==. (utxo Psql.^. SwapUtxoSwapIntoLnId)
        )
      Psql.where_
        ( ( ( swap Psql.^. SwapIntoLnStatus
                Psql.==. Psql.val SwapExpired
            )
              Psql.&&. ( utxo Psql.^. SwapUtxoStatus
                           `Psql.in_` Psql.valList
                             [ SwapUtxoUnspent,
                               SwapUtxoUnspentChanReserve
                             ]
                       )
          )
            Psql.||. ( ( swap Psql.^. SwapIntoLnStatus
                           Psql.==. Psql.val SwapSucceeded
                       )
                         Psql.&&. ( utxo Psql.^. SwapUtxoStatus
                                      Psql.==. Psql.val
                                        SwapUtxoUnspent
                                  )
                     )
        )
      pure (utxo, swap)

getUtxosBySwapIdSql ::
  ( MonadIO m
  ) =>
  SwapIntoLnId ->
  ReaderT Psql.SqlBackend m [Entity SwapUtxo]
getUtxosBySwapIdSql swapId = do
  Psql.select $
    Psql.from $ \row -> do
      Psql.locking Psql.ForUpdate
      Psql.where_
        ( row Psql.^. SwapUtxoSwapIntoLnId
            Psql.==. Psql.val swapId
        )
      pure row

updateRefundBlockIdSql ::
  ( MonadIO m
  ) =>
  BlockId ->
  ReaderT Psql.SqlBackend m ()
updateRefundBlockIdSql blkId = do
  utxos <- Psql.select $
    Psql.from $ \row -> do
      Psql.where_
        ( row Psql.^. SwapUtxoBlockId
            Psql.==. Psql.val blkId
        )
      pure row
  Psql.update $ \row -> do
    Psql.set
      row
      [ SwapUtxoRefundBlockId
          Psql.=. Psql.val (Just blkId)
      ]
    Psql.where_ $
      row Psql.^. SwapUtxoRefundTxId
        `Psql.in_` Psql.valList (Just <$> (swapUtxoTxid . entityVal <$> utxos))
        Psql.&&. ( row Psql.^. SwapUtxoStatus
                     Psql.==. Psql.val SwapUtxoSpentRefund
                 )

updateOrphanSql ::
  ( MonadIO m
  ) =>
  [BlockId] ->
  ReaderT Psql.SqlBackend m ()
updateOrphanSql ids = do
  ct <- getCurrentTime
  Psql.update $ \row -> do
    Psql.set
      row
      [ SwapUtxoStatus
          Psql.=. Psql.val SwapUtxoOrphan,
        SwapUtxoUpdatedAt
          Psql.=. Psql.val ct
      ]
    Psql.where_ $
      row Psql.^. SwapUtxoBlockId
        `Psql.in_` Psql.valList ids

revertRefundedSql ::
  ( MonadIO m
  ) =>
  [BlockId] ->
  ReaderT Psql.SqlBackend m ()
revertRefundedSql ids = do
  ct <- getCurrentTime
  Psql.update $ \row -> do
    Psql.set
      row
      [ SwapUtxoStatus
          Psql.=. Psql.val SwapUtxoUnspent,
        SwapUtxoRefundTxId
          Psql.=. Psql.val Nothing,
        SwapUtxoRefundBlockId
          Psql.=. Psql.val Nothing,
        SwapUtxoUpdatedAt
          Psql.=. Psql.val ct
      ]
    Psql.where_ $
      row Psql.^. SwapUtxoRefundBlockId
        `Psql.in_` Psql.valList (Just <$> ids)
        Psql.&&. ( row Psql.^. SwapUtxoStatus
                     Psql.==. Psql.val SwapUtxoSpentRefund
                 )