content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE TypeOperators     #-}
  
  module Cardano.Wallet.API.V1.Handlers.Transactions (
        handlers
      , newPayment
      , newIssurance
      , getTransactionsHistory
      , estimateFees
      -- | Helper converter.
      , txFromMeta
      ) where
  
  import           Universum
  
  import           Servant
  
  import           Data.Coerce (coerce)
  
  import           Pos.Chain.Txp (TxId)
  import           Pos.Core (Address, Timestamp)
  
  import           Cardano.Wallet.API.Request
  import           Cardano.Wallet.API.Response
  import qualified Cardano.Wallet.API.V1.Transactions as Transactions
  import           Cardano.Wallet.API.V1.Types
  import           Cardano.Wallet.Kernel.DB.HdWallet (UnknownHdAccount)
  import           Cardano.Wallet.Kernel.DB.TxMeta (TxMeta)
  import           Cardano.Wallet.WalletLayer (ActiveWalletLayer,
                       NewPaymentError (..), PassiveWalletLayer)
  import qualified Cardano.Wallet.WalletLayer as WalletLayer
  
  handlers :: ActiveWalletLayer IO -> ServerT Transactions.API Handler
  handlers aw = newPayment aw
           :<|> newIssurance aw
           :<|> getTransactionsHistory (WalletLayer.walletPassiveLayer aw)
           :<|> estimateFees aw
  
  -- | Given a 'Payment' as input, tries to generate a new 'Pay Transaction', submitting
  -- it to the network eventually.
  newPayment :: ActiveWalletLayer IO
             -> Payment
             -> Handler (APIResponse Transaction)
  newPayment aw payment@Payment{..} = liftIO $ do
  
      res <- liftIO $ (WalletLayer.pay aw) (maybe mempty coerce pmtSpendingPassword)
                                           payment
      case res of
           Left err        -> throwM err
           Right (_, meta) -> txFromMeta aw NewPaymentUnknownAccountId meta
  
  -- | Given a 'Issurance' as input, tries to generate a new 'Issue Transaction', submitting
  -- it to the network eventually.
  newIssurance :: ActiveWalletLayer IO
               -> Issurance
               -> Handler (APIResponse Transaction)
  newIssurance aw issurance@Issurance{..} = liftIO $ do
  
      res <- liftIO $ (WalletLayer.issue aw) (maybe mempty coerce issSpendingPassword)
                                           issurance
      case res of
           Left err        -> throwM err
           Right (_, meta) -> txFromMeta aw NewPaymentUnknownAccountId meta
  
  txFromMeta :: Exception e
             => ActiveWalletLayer IO
             -> (UnknownHdAccount -> e)
             -> TxMeta
             -> IO (APIResponse Transaction)
  txFromMeta aw embedErr meta = do
      mTx <- WalletLayer.getTxFromMeta (WalletLayer.walletPassiveLayer aw) meta
      case mTx of
        Left err -> throwM (embedErr err)
        Right tx -> return $ single tx
  
  getTransactionsHistory :: PassiveWalletLayer IO
                         -> Maybe WalletId
                         -> Maybe AccountIndex
                         -> Maybe (V1 Address)
                         -> RequestParams
                         -> FilterOperations '[V1 TxId, V1 Timestamp] Transaction
                         -> SortOperations Transaction
                         -> Handler (APIResponse [Transaction])
  getTransactionsHistory pw mwalletId mAccIdx mAddr requestParams fops sops =
      liftIO $ do
          mRes <- WalletLayer.getTransactions pw mwalletId mAccIdx mAddr requestParams fops sops
          case mRes of
              Left err  -> throwM err
              Right res -> return res
  
  -- | Computes the fees generated by this payment, without actually sending
  -- the transaction to the network.
  estimateFees :: ActiveWalletLayer IO
               -> Payment
               -> Handler (APIResponse EstimatedFees)
  estimateFees aw payment@Payment{..} = do
      res <- liftIO $ (WalletLayer.estimateFees aw) payment
      case res of
           Left err  -> throwM err
           Right fee -> return $ single (EstimatedFees (V1 fee))
  