packages feed

haskoin-wallet-0.0.1: Network/Haskoin/Wallet/Store/DbCoin.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GADTs             #-}
{-# LANGUAGE TypeFamilies      #-}
module Network.Haskoin.Wallet.Store.DbCoin 
( dbCoins
, dbBalance
, yamlCoin
, toCoin
) where

import Control.Applicative ((<$>))
import Control.Monad.Trans.Either (EitherT)

import Data.Yaml
    ( Value 
    , object 
    , (.=)
    )
import Data.Maybe (isJust, fromJust)

import Database.Persist
    ( PersistStore
    , PersistQuery
    , PersistMonadBackend
    , Entity(..)
    , entityVal
    , selectList
    , (==.)
    , SelectOpt(Asc)
    )
import Database.Persist.Sqlite (SqlBackend)

import Network.Haskoin.Wallet.TxBuilder
import Network.Haskoin.Wallet.Store.Util
import Network.Haskoin.Protocol
import Network.Haskoin.Util

toCoin :: DbCoinGeneric b -> Either String Coin
toCoin c = do
    scp <- decodeScriptOps =<< maybeToEither scpErr (hexToBS $ dbCoinScript c)
    rdm <- if isJust $ dbCoinRdmScript c
        then do
            bs <- maybeToEither rdmErr $ hexToBS =<< dbCoinRdmScript c
            Just <$> decodeScriptOps bs
        else return Nothing
    h <- maybeToEither tidErr $ decodeTxid $ dbCoinTxid c
    return $ Coin (TxOut (fromIntegral $ dbCoinValue c) scp)
                  (OutPoint h (fromIntegral $ dbCoinPos c))
                  rdm
  where
    scpErr = "toCoin: Could not decode coin script"
    tidErr = "toCoin: Could not decode coin txid"
    rdmErr = "toCoin: Could not decode coin redeem script"

yamlCoin :: DbCoinGeneric b -> Value
yamlCoin coin = object $ concat
    [ [ "TxID"    .= dbCoinTxid coin 
      , "Index"   .= dbCoinPos coin
      , "Value"   .= dbCoinValue coin
      , "Script"  .= dbCoinScript coin
      , "Address" .= dbCoinAddress coin
      ] 
    , if isJust $ dbCoinRdmScript coin 
        then ["Redeem" .= fromJust (dbCoinRdmScript coin)] 
        else []
    , if dbCoinOrphan coin then ["Orphan" .= True] else []
    ]

dbBalance :: (PersistQuery m, PersistMonadBackend m ~ b)
          => Entity (DbAccountGeneric b)
          -> EitherT String m Int
dbBalance (Entity ai _) = do
    coins <- selectList 
        [ DbCoinAccount ==. ai
        , DbCoinStatus  ==. Unspent
        , DbCoinOrphan  ==. False
        ] []
    return $ sum $ map (dbCoinValue . entityVal) coins

dbCoins :: (PersistQuery m, PersistMonadBackend m ~ SqlBackend) 
        => DbAccountId 
        -> EitherT String m [DbCoinGeneric SqlBackend]
dbCoins ai = do
    coins <- selectList 
        [ DbCoinAccount ==. ai
        , DbCoinStatus  ==. Unspent
        , DbCoinOrphan  ==. False
        ] [Asc DbCoinCreated]
    return $ map entityVal coins