lnd-client-0.1.0.1: src/LndClient/Data/Newtype.hs
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module LndClient.Data.Newtype
( AddIndex (..),
SettleIndex (..),
PaymentRequest (..),
RHash (..),
RPreimage (..),
MSat (..),
toGrpcSat,
toGrpcMSat,
toGrpcMaybe,
fromGrpcSat,
fromGrpcMSat,
CipherSeedMnemonic (..),
AezeedPassphrase (..),
Seconds (..),
NodePubKey (..),
NodeLocation (..),
GrpcTimeoutSeconds,
newRHash,
newRPreimage,
newPendingChanId,
newGrpcTimeout,
unGrpcTimeout,
defaultSyncGrpcTimeout,
defaultAsyncGrpcTimeout,
TxId (..),
Vout (..),
ChanId (..),
PendingChannelId (..),
Psbt (..),
RawTx (..)
)
where
import Codec.QRCode as QR (ToText)
import qualified Crypto.Hash.SHA256 as SHA256 (hash)
import Crypto.Random (getRandomBytes)
import Data.ByteString.Base16 as B16 (decode, encode)
import Data.ByteString.Char8 as C8
import Data.ProtoLens.Message
import LndClient.Class
import LndClient.Data.Kind
import LndClient.Data.Type
import LndClient.Import.External
import LndClient.Util
import qualified Proto.Invoicesrpc.Invoices as IGrpc
import qualified Proto.Invoicesrpc.Invoices_Fields as IGrpc
import qualified Proto.Lnrpc.Ln1 as LnGrpc
import qualified Proto.Lnrpc.Ln1_Fields as LnGrpc
newtype PendingChannelId = PendingChannelId ByteString
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show)
deriving stock (Generic)
instance Out PendingChannelId
newtype Psbt = Psbt ByteString
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show)
deriving stock (Generic)
instance Out Psbt
newtype RawTx = RawTx ByteString
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show)
deriving stock (Generic)
instance Out RawTx
newtype ChanId = ChanId Word64
deriving newtype
( PersistField,
PersistFieldSql,
Eq,
Ord,
Show,
Read
)
deriving stock (Generic)
instance Out ChanId
newtype Vout (a :: TxKind) = Vout Word32
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show, Read)
deriving stock (Generic)
instance Out (Vout a)
newtype TxId (a :: TxKind) = TxId ByteString
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show, Read)
deriving stock (Generic)
instance Out (TxId a)
newtype NodePubKey = NodePubKey ByteString
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show, Read)
deriving stock (Generic)
instance Out NodePubKey
newtype NodeLocation = NodeLocation Text
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show, Read)
deriving stock (Generic)
instance Out NodeLocation
newtype AddIndex = AddIndex Word64
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show)
deriving stock (Generic)
instance Out AddIndex
newtype SettleIndex = SettleIndex Word64
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show)
deriving stock (Generic)
instance Out SettleIndex
newtype PaymentRequest = PaymentRequest Text
deriving newtype (PersistField, PersistFieldSql, Eq, QR.ToText, Show)
deriving stock (Generic)
instance Out PaymentRequest
newtype RHash = RHash ByteString
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show)
deriving stock (Generic)
instance Out RHash
newtype RPreimage = RPreimage ByteString
deriving newtype (PersistField, PersistFieldSql, Eq, Ord, Show)
deriving stock (Generic)
instance Out RPreimage
newtype MSat = MSat Word64
deriving newtype
( PersistField,
PersistFieldSql,
Eq,
Num,
Ord,
FromJSON,
Show,
Read
)
deriving stock
( Generic
)
instance Out MSat
newtype CipherSeedMnemonic = CipherSeedMnemonic [Text]
deriving newtype (PersistField, PersistFieldSql, Eq, FromJSON)
newtype AezeedPassphrase = AezeedPassphrase Text
deriving newtype (PersistField, PersistFieldSql, Eq, FromJSON)
newtype Seconds = Seconds Word64
deriving newtype
( PersistField,
PersistFieldSql,
Eq,
Ord,
FromJSON,
Show,
Num,
Real,
Enum,
Integral
)
deriving stock (Generic)
instance Out Seconds
newtype GrpcTimeoutSeconds = GrpcTimeoutSeconds Int
deriving newtype (Eq, Ord, FromJSON, Show)
instance ToGrpc NodePubKey ByteString where
toGrpc = Right . coerce
instance ToGrpc NodePubKey Text where
toGrpc =
first (const $ ToGrpcError "UTF8_DECODE_ERROR")
. decodeUtf8'
. B16.encode
. coerce
instance ToGrpc NodeLocation Text where
toGrpc = Right . coerce
--
-- TODO : smart constructors for NodePubKey and NodeLocation ???
--
instance FromGrpc (TxId a) ByteString where
fromGrpc = Right . TxId
instance FromGrpc (TxId a) Text where
fromGrpc = (TxId <$>) . txIdParser
instance FromGrpc (Vout a) Word32 where
fromGrpc = Right . Vout
instance FromGrpc NodePubKey ByteString where
fromGrpc = Right . NodePubKey
instance FromGrpc NodePubKey Text where
fromGrpc =
bimap (const $ FromGrpcError "NodePubKey hex decoding error") NodePubKey . B16.decode . encodeUtf8
instance FromGrpc NodeLocation Text where
fromGrpc = Right . NodeLocation
instance ToGrpc (TxId a) ByteString where
toGrpc = Right . coerce
instance ToGrpc (Vout a) Word32 where
toGrpc = Right . coerce
instance ToGrpc ChanId Word64 where
toGrpc = Right . coerce
instance ToGrpc PendingChannelId ByteString where
toGrpc = Right . coerce
instance ToGrpc Psbt ByteString where
toGrpc = Right . coerce
instance ToGrpc RawTx ByteString where
toGrpc = Right . coerce
instance ToGrpc AddIndex Word64 where
toGrpc = Right . coerce
instance ToGrpc SettleIndex Word64 where
toGrpc = Right . coerce
instance FromGrpc ChanId Word64 where
fromGrpc = Right . coerce
instance FromGrpc RHash ByteString where
fromGrpc = Right . RHash
instance FromGrpc RPreimage ByteString where
fromGrpc = Right . RPreimage
instance FromGrpc Psbt ByteString where
fromGrpc = Right . Psbt
instance FromGrpc AddIndex Word64 where
fromGrpc = Right . AddIndex
instance FromGrpc SettleIndex Word64 where
fromGrpc = Right . SettleIndex
instance FromGrpc PaymentRequest Text where
fromGrpc = Right . PaymentRequest
instance FromGrpc PaymentRequest IGrpc.AddHoldInvoiceResp where
fromGrpc x = fromGrpc (x ^. IGrpc.paymentRequest)
instance FromGrpc Seconds Int64 where
fromGrpc =
(Seconds <$>)
. maybeToRight (FromGrpcError "Seconds overflow")
. safeFromIntegral
instance FromGrpc RHash Text where
fromGrpc x0 =
case B16.decode $ encodeUtf8 x0 of
Right x1 -> Right $ RHash x1
Left {} -> Left $ FromGrpcError "NON_HEX_RHASH"
instance FromGrpc RPreimage Text where
fromGrpc x0 =
case B16.decode $ encodeUtf8 x0 of
Right x1 -> Right $ RPreimage x1
Left {} -> Left $ FromGrpcError "NON_HEX_RPREIMAGE"
instance ToGrpc PaymentRequest Text where
toGrpc x = Right (coerce x :: Text)
instance ToGrpc Seconds Int64 where
toGrpc x =
maybeToRight
(ToGrpcError "Seconds overflow")
$ safeFromIntegral (coerce x :: Word64)
instance ToGrpc CipherSeedMnemonic [Text] where
toGrpc = Right . coerce
instance ToGrpc AezeedPassphrase ByteString where
toGrpc x = Right $ encodeUtf8 (coerce x :: Text)
instance ToGrpc RHash ByteString where
toGrpc = Right . coerce
instance ToGrpc RHash IGrpc.CancelInvoiceMsg where
toGrpc x = do
ph <- toGrpc x
Right $ defMessage & IGrpc.paymentHash .~ ph
instance ToGrpc RPreimage ByteString where
toGrpc = Right . coerce
instance ToGrpc RPreimage IGrpc.SettleInvoiceMsg where
toGrpc x = do
p <- toGrpc x
Right $ defMessage & IGrpc.preimage .~ p
instance ToGrpc PaymentRequest LnGrpc.PayReqString where
toGrpc x = Right $ defMessage & LnGrpc.payReq .~ coerce x
instance ToGrpc RHash LnGrpc.PaymentHash where
toGrpc x = Right $ defMessage & LnGrpc.rHash .~ coerce x
instance ToGrpc RHash IGrpc.SubscribeSingleInvoiceRequest where
toGrpc x = do
rh <- toGrpc x
Right $ defMessage & IGrpc.rHash .~ rh
newRHash :: RPreimage -> RHash
newRHash = RHash . SHA256.hash . coerce
newRPreimage :: MonadIO m => m RPreimage
newRPreimage = RPreimage <$> liftIO (getRandomBytes 32)
newPendingChanId :: MonadIO m => m PendingChannelId
newPendingChanId = PendingChannelId <$> liftIO (getRandomBytes 32)
newGrpcTimeout :: Int -> Maybe GrpcTimeoutSeconds
newGrpcTimeout x =
if x > 0
then Just $ GrpcTimeoutSeconds x
else Nothing
unGrpcTimeout :: GrpcTimeoutSeconds -> Int
unGrpcTimeout = coerce
defaultSyncGrpcTimeout :: GrpcTimeoutSeconds
defaultSyncGrpcTimeout = GrpcTimeoutSeconds 60
defaultAsyncGrpcTimeout :: GrpcTimeoutSeconds
defaultAsyncGrpcTimeout = GrpcTimeoutSeconds 3600
toGrpcSat :: (Integral a, Bounded a) => MSat -> Either LndError a
toGrpcSat mSat = do
let mVal :: Word64 = coerce mSat
case divMod mVal 1000 of
(val, 0) -> maybeToRight (ToGrpcError "MSat overflow") $ safeFromIntegral val
_ -> Left $ ToGrpcError ("Cannot convert " <> inspect mVal <> " to Sat")
fromGrpcSat :: (Integral a) => a -> Either LndError MSat
fromGrpcSat sat =
maybeToRight
(FromGrpcError ("Cannot convert " <> (inspect . toInteger) sat <> " to MSat"))
$ MSat . (1000 *) <$> safeFromIntegral sat
toGrpcMSat :: (Integral a, Bounded a) => MSat -> Either LndError a
toGrpcMSat x =
maybeToRight
(ToGrpcError "MSat overflow")
$ safeFromIntegral (coerce x :: Word64)
toGrpcMaybe :: (ToGrpc a b) => Maybe a -> Either LndError (Maybe b)
toGrpcMaybe (Just fs) = Just <$> toGrpc fs
toGrpcMaybe Nothing = Right Nothing
fromGrpcMSat :: (Integral a) => a -> Either LndError MSat
fromGrpcMSat x =
maybeToRight
(FromGrpcError "MSat overflow")
$ MSat <$> safeFromIntegral x