module Data.Bitcoin.PaymentChannel.Internal.BitcoinAmount where
import qualified Data.Serialize as Ser
import qualified Data.Serialize.Put as SerPut
import qualified Data.Serialize.Get as SerGet
import qualified Data.Binary as Bin
import qualified Data.Binary.Put as BinPut
import qualified Data.Binary.Get as BinGet
import Data.Word
newtype BitcoinAmount = BitcoinAmount Integer
deriving (Eq, Ord)
instance Show BitcoinAmount where
show amount = show (toInteger amount) ++ " satoshi"
instance Num BitcoinAmount where
(BitcoinAmount a1) * (BitcoinAmount a2) = BitcoinAmount (fromIntegral . capToWord64 $ a1*a2)
(BitcoinAmount a1) + (BitcoinAmount a2) = BitcoinAmount (fromIntegral . capToWord64 $ a1+a2)
(BitcoinAmount a1) - (BitcoinAmount a2) = BitcoinAmount (fromIntegral . capToWord64 $ a1-a2)
abs = id
signum (BitcoinAmount 0) = BitcoinAmount 0
signum (BitcoinAmount _) = BitcoinAmount 1
fromInteger = BitcoinAmount . fromIntegral . capToWord64
instance Enum BitcoinAmount where
toEnum = BitcoinAmount . fromIntegral . capToWord64 . fromIntegral
fromEnum (BitcoinAmount amount) = fromIntegral amount
instance Real BitcoinAmount where
toRational (BitcoinAmount amount) = toRational amount
instance Integral BitcoinAmount where
toInteger (BitcoinAmount int) = int
quotRem (BitcoinAmount _) (BitcoinAmount _) =
error "Division of two BitcoinAmounts is undefined"
capToWord64 :: Integer -> Word64
capToWord64 i = fromIntegral $
max 0 cappedValue
where
cappedValue = min i $ fromIntegral (maxBound :: Word64)
instance Bin.Binary BitcoinAmount where
put = BinPut.putWord64le . fromIntegral . toInteger
get = BitcoinAmount . fromIntegral <$> BinGet.getWord64le
instance Ser.Serialize BitcoinAmount where
put = SerPut.putWord64le . fromIntegral . toInteger
get = BitcoinAmount . fromIntegral <$> SerGet.getWord64le