{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Cardano.Wallet.Unsafe
( unsafeRight
, unsafeFromHex
, unsafeFromHexText
, unsafeFromBase64
, unsafeFromHexFile
, unsafeDecodeAddress
, unsafeDecodeHex
, unsafeFromText
, unsafeRunExceptT
, unsafeXPrv
, unsafeXPub
, unsafeDeserialiseCbor
, unsafeBech32DecodeFile
, unsafeBech32Decode
, unsafeMkPercentage
, unsafeIntToWord
, someDummyMnemonic
, unsafeMkMnemonic
, unsafeMkEntropy
, unsafeMkSomeMnemonicFromEntropy
) where
import Prelude
import Cardano.Crypto.Wallet
( XPrv, XPub )
import Cardano.Mnemonic
( ConsistentEntropy
, Entropy
, EntropySize
, Mnemonic
, MnemonicWords
, SomeMnemonic (..)
, ValidChecksumSize
, ValidEntropySize
, ValidMnemonicSentence
, entropyToMnemonic
, mkEntropy
, mkMnemonic
)
import Cardano.Wallet.Api.Types
( DecodeAddress (..) )
import Cardano.Wallet.Primitive.Types.Address
( Address )
import Cardano.Wallet.Util
( internalError )
import Control.Monad
( (>=>) )
import Control.Monad.Trans.Except
( ExceptT (..), runExceptT )
import Data.Binary.Get
( Get, runGet )
import Data.ByteArray
( ByteArray )
import Data.ByteArray.Encoding
( Base (..), convertFromBase )
import Data.ByteString
( ByteString )
import Data.Char
( isHexDigit )
import Data.Either
( fromRight )
import Data.Proxy
( Proxy (..) )
import Data.Quantity
( Percentage, mkPercentage )
import Data.Text
( Text )
import Data.Text.Class
( FromText (..) )
import Data.Typeable
( Typeable, typeRep )
import Fmt
( Buildable, Builder, build, (+||), (|+), (||+) )
import GHC.Stack
( HasCallStack )
import GHC.TypeLits
( natVal )
import qualified Cardano.Crypto.Wallet as CC
import qualified Codec.Binary.Bech32 as Bech32
import qualified Codec.CBOR.Decoding as CBOR
import qualified Codec.CBOR.Read as CBOR
import qualified Data.ByteArray as BA
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy as BL
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.IO as TIO
unsafeRight :: (Buildable e, HasCallStack) => Either e a -> a
unsafeRight :: Either e a -> a
unsafeRight = (e -> a) -> (a -> a) -> Either e a -> a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Builder -> a
forall a. HasCallStack => Builder -> a
internalError (Builder -> a) -> (e -> Builder) -> e -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> Builder
forall p. Buildable p => p -> Builder
build) a -> a
forall a. a -> a
id
unsafeFromHex :: forall b. (HasCallStack, ByteArray b) => ByteString -> b
unsafeFromHex :: ByteString -> b
unsafeFromHex = Either String b -> b
forall e a. (Buildable e, HasCallStack) => Either e a -> a
unsafeRight (Either String b -> b)
-> (ByteString -> Either String b) -> ByteString -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base -> ByteString -> Either String b
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
Base -> bin -> Either String bout
convertFromBase @ByteString @b Base
Base16
unsafeFromHexText :: HasCallStack => Text -> ByteString
unsafeFromHexText :: Text -> ByteString
unsafeFromHexText = ByteString -> ByteString
forall b. (HasCallStack, ByteArray b) => ByteString -> b
unsafeFromHex (ByteString -> ByteString)
-> (Text -> ByteString) -> Text -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
T.encodeUtf8
unsafeFromBase64 :: HasCallStack => ByteString -> ByteString
unsafeFromBase64 :: ByteString -> ByteString
unsafeFromBase64 = Either String ByteString -> ByteString
forall e a. (Buildable e, HasCallStack) => Either e a -> a
unsafeRight (Either String ByteString -> ByteString)
-> (ByteString -> Either String ByteString)
-> ByteString
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base -> ByteString -> Either String ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
Base -> bin -> Either String bout
convertFromBase @ByteString @ByteString Base
Base64
unsafeFromHexFile :: HasCallStack => FilePath -> IO ByteString
unsafeFromHexFile :: String -> IO ByteString
unsafeFromHexFile = (ByteString -> ByteString) -> IO ByteString -> IO ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteString -> ByteString
forall b. (HasCallStack, ByteArray b) => ByteString -> b
unsafeFromHex (ByteString -> ByteString)
-> (ByteString -> ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ByteString -> ByteString
B8.filter Char -> Bool
isHexDigit) (IO ByteString -> IO ByteString)
-> (String -> IO ByteString) -> String -> IO ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO ByteString
B8.readFile
unsafeDecodeAddress
:: forall n. (HasCallStack, DecodeAddress n)
=> Text
-> Address
unsafeDecodeAddress :: Text -> Address
unsafeDecodeAddress = Either TextDecodingError Address -> Address
forall e a. (Buildable e, HasCallStack) => Either e a -> a
unsafeRight (Either TextDecodingError Address -> Address)
-> (Text -> Either TextDecodingError Address) -> Text -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DecodeAddress n => Text -> Either TextDecodingError Address
forall (n :: NetworkDiscriminant).
DecodeAddress n =>
Text -> Either TextDecodingError Address
decodeAddress @n
unsafeDecodeHex :: HasCallStack => Get a -> ByteString -> a
unsafeDecodeHex :: Get a -> ByteString -> a
unsafeDecodeHex Get a
get = Get a -> ByteString -> a
forall a. Get a -> ByteString -> a
runGet Get a
get (ByteString -> a) -> (ByteString -> ByteString) -> ByteString -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.fromStrict (ByteString -> ByteString)
-> (ByteString -> ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
forall b. (HasCallStack, ByteArray b) => ByteString -> b
unsafeFromHex
unsafeFromText :: (FromText a, HasCallStack) => Text -> a
unsafeFromText :: Text -> a
unsafeFromText = Either TextDecodingError a -> a
forall e a. (Buildable e, HasCallStack) => Either e a -> a
unsafeRight (Either TextDecodingError a -> a)
-> (Text -> Either TextDecodingError a) -> Text -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either TextDecodingError a
forall a. FromText a => Text -> Either TextDecodingError a
fromText
unsafeXPrv :: HasCallStack => ByteString -> XPrv
unsafeXPrv :: ByteString -> XPrv
unsafeXPrv ByteString
bytes =
case ByteString -> Either String XPrv
forall bin. ByteArrayAccess bin => bin -> Either String XPrv
CC.xprv ByteString
bytes of
Left String
e -> String -> XPrv
forall a. HasCallStack => String -> a
error (String -> XPrv) -> String -> XPrv
forall a b. (a -> b) -> a -> b
$ String
"unsafeXPrv: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
e
Right XPrv
a -> XPrv
a
unsafeXPub :: HasCallStack => ByteString -> XPub
unsafeXPub :: ByteString -> XPub
unsafeXPub ByteString
bytes =
case ByteString -> Either String XPub
CC.xpub ByteString
bytes of
Left String
e -> String -> XPub
forall a. HasCallStack => String -> a
error (String -> XPub) -> String -> XPub
forall a b. (a -> b) -> a -> b
$ String
"unsafeXPub: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
e
Right XPub
a -> XPub
a
unsafeMkMnemonic
:: forall mw n csz
. (ConsistentEntropy n mw csz, EntropySize mw ~ n, HasCallStack)
=> [Text]
-> Mnemonic mw
unsafeMkMnemonic :: [Text] -> Mnemonic mw
unsafeMkMnemonic [Text]
m =
case [Text] -> Either (MkMnemonicError csz) (Mnemonic mw)
forall (mw :: Nat) (ent :: Nat) (csz :: Nat).
(ConsistentEntropy ent mw csz, EntropySize mw ~ ent) =>
[Text] -> Either (MkMnemonicError csz) (Mnemonic mw)
mkMnemonic [Text]
m of
Left MkMnemonicError csz
e -> String -> Mnemonic mw
forall a. HasCallStack => String -> a
error (String -> Mnemonic mw) -> String -> Mnemonic mw
forall a b. (a -> b) -> a -> b
$ String
"unsafeMnemonic: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> MkMnemonicError csz -> String
forall a. Show a => a -> String
show MkMnemonicError csz
e
Right Mnemonic mw
a -> Mnemonic mw
a
unsafeRunExceptT :: (MonadFail m, Show e) => ExceptT e m a -> m a
unsafeRunExceptT :: ExceptT e m a -> m a
unsafeRunExceptT = ExceptT e m a -> m (Either e a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT e m a -> m (Either e a))
-> (Either e a -> m a) -> ExceptT e m a -> m a
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> \case
Left e
e ->
String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> m a) -> String -> m a
forall a b. (a -> b) -> a -> b
$ String
"unexpected error: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> e -> String
forall a. Show a => a -> String
show e
e
Right a
a ->
a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a
unsafeDeserialiseCbor
:: HasCallStack
=> (forall s. CBOR.Decoder s a)
-> BL.ByteString
-> a
unsafeDeserialiseCbor :: (forall s. Decoder s a) -> ByteString -> a
unsafeDeserialiseCbor forall s. Decoder s a
decoder ByteString
bytes = (DeserialiseFailure -> a)
-> ((ByteString, a) -> a)
-> Either DeserialiseFailure (ByteString, a)
-> a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
(\DeserialiseFailure
e -> String -> a
forall a. HasCallStack => String -> a
error (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ String
"unsafeSerializeCbor: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> DeserialiseFailure -> String
forall a. Show a => a -> String
show DeserialiseFailure
e)
(ByteString, a) -> a
forall a b. (a, b) -> b
snd
((forall s. Decoder s a)
-> ByteString -> Either DeserialiseFailure (ByteString, a)
forall a.
(forall s. Decoder s a)
-> ByteString -> Either DeserialiseFailure (ByteString, a)
CBOR.deserialiseFromBytes forall s. Decoder s a
decoder ByteString
bytes)
unsafeMkEntropy
:: forall ent csz.
( HasCallStack
, ValidEntropySize ent
, ValidChecksumSize ent csz
)
=> ByteString
-> Entropy ent
unsafeMkEntropy :: ByteString -> Entropy ent
unsafeMkEntropy = (EntropyError csz -> Entropy ent)
-> (Entropy ent -> Entropy ent)
-> Either (EntropyError csz) (Entropy ent)
-> Entropy ent
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> Entropy ent
forall a. HasCallStack => String -> a
error (String -> Entropy ent)
-> (EntropyError csz -> String) -> EntropyError csz -> Entropy ent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EntropyError csz -> String
forall a. Show a => a -> String
show) Entropy ent -> Entropy ent
forall a. a -> a
id (Either (EntropyError csz) (Entropy ent) -> Entropy ent)
-> (ByteString -> Either (EntropyError csz) (Entropy ent))
-> ByteString
-> Entropy ent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScrubbedBytes -> Either (EntropyError csz) (Entropy ent)
forall (ent :: Nat) (csz :: Nat).
(ValidEntropySize ent, ValidChecksumSize ent csz) =>
ScrubbedBytes -> Either (EntropyError csz) (Entropy ent)
mkEntropy (ScrubbedBytes -> Either (EntropyError csz) (Entropy ent))
-> (ByteString -> ScrubbedBytes)
-> ByteString
-> Either (EntropyError csz) (Entropy ent)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ScrubbedBytes
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
BA.convert
unsafeMkSomeMnemonicFromEntropy
:: forall mw ent csz.
( HasCallStack
, ValidEntropySize ent
, ValidChecksumSize ent csz
, ValidMnemonicSentence mw
, ent ~ EntropySize mw
, mw ~ MnemonicWords ent
)
=> Proxy mw
-> ByteString
-> SomeMnemonic
unsafeMkSomeMnemonicFromEntropy :: Proxy mw -> ByteString -> SomeMnemonic
unsafeMkSomeMnemonicFromEntropy Proxy mw
_ = Mnemonic mw -> SomeMnemonic
forall (mw :: Nat). KnownNat mw => Mnemonic mw -> SomeMnemonic
SomeMnemonic
(Mnemonic mw -> SomeMnemonic)
-> (ByteString -> Mnemonic mw) -> ByteString -> SomeMnemonic
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Entropy ent -> Mnemonic mw
forall (mw :: Nat) (ent :: Nat) (csz :: Nat).
(ValidMnemonicSentence mw, ValidEntropySize ent,
ValidChecksumSize ent csz, ent ~ EntropySize mw,
mw ~ MnemonicWords ent) =>
Entropy ent -> Mnemonic mw
entropyToMnemonic
(Entropy ent -> Mnemonic mw)
-> (ByteString -> Entropy ent) -> ByteString -> Mnemonic mw
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (csz :: Nat).
(HasCallStack, ValidEntropySize ent, ValidChecksumSize ent csz) =>
ByteString -> Entropy ent
forall (ent :: Nat) (csz :: Nat).
(HasCallStack, ValidEntropySize ent, ValidChecksumSize ent csz) =>
ByteString -> Entropy ent
unsafeMkEntropy @ent
someDummyMnemonic
:: forall mw ent csz.
( HasCallStack
, ValidEntropySize ent
, ValidChecksumSize ent csz
, ValidMnemonicSentence mw
, ent ~ EntropySize mw
, mw ~ MnemonicWords ent
)
=> Proxy mw
-> SomeMnemonic
someDummyMnemonic :: Proxy mw -> SomeMnemonic
someDummyMnemonic Proxy mw
proxy =
let
n :: Int
n = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy ent -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy ent
forall k (t :: k). Proxy t
Proxy @ent) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
8
entropy :: ByteString
entropy = Int -> Word8 -> ByteString
BS.replicate Int
n Word8
0
in
Proxy mw -> ByteString -> SomeMnemonic
forall (mw :: Nat) (ent :: Nat) (csz :: Nat).
(HasCallStack, ValidEntropySize ent, ValidChecksumSize ent csz,
ValidMnemonicSentence mw, ent ~ EntropySize mw,
mw ~ MnemonicWords ent) =>
Proxy mw -> ByteString -> SomeMnemonic
unsafeMkSomeMnemonicFromEntropy Proxy mw
proxy ByteString
entropy
unsafeBech32DecodeFile :: HasCallStack => FilePath -> IO BL.ByteString
unsafeBech32DecodeFile :: String -> IO ByteString
unsafeBech32DecodeFile = (Text -> ByteString) -> IO Text -> IO ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (HasCallStack => Text -> ByteString
Text -> ByteString
unsafeBech32Decode (Text -> ByteString) -> (Text -> Text) -> Text -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
firstLine) (IO Text -> IO ByteString)
-> (String -> IO Text) -> String -> IO ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO Text
TIO.readFile
where
firstLine :: Text -> Text
firstLine = (Char -> Bool) -> Text -> Text
T.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\n')
unsafeBech32Decode :: HasCallStack => Text -> BL.ByteString
unsafeBech32Decode :: Text -> ByteString
unsafeBech32Decode Text
txt = case Text -> Either DecodingError (HumanReadablePart, DataPart)
Bech32.decodeLenient Text
txt of
Right (HumanReadablePart
_hrp, DataPart
dp) -> ByteString
-> (ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> ByteString
bomb String
"missing data part")
ByteString -> ByteString
BL.fromStrict (DataPart -> Maybe ByteString
Bech32.dataPartToBytes DataPart
dp)
Left DecodingError
e -> String -> ByteString
bomb (DecodingError -> String
forall a. Show a => a -> String
show DecodingError
e)
where
bomb :: String -> ByteString
bomb String
msg = String -> ByteString
forall a. HasCallStack => String -> a
error (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ String
"Could not decode bech32 string " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
forall a. Show a => a -> String
show Text
txt
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" because " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
msg
unsafeMkPercentage :: HasCallStack => Rational -> Percentage
unsafeMkPercentage :: Rational -> Percentage
unsafeMkPercentage Rational
r = Percentage -> Either MkPercentageError Percentage -> Percentage
forall b a. b -> Either a b -> b
fromRight Percentage
bomb (Either MkPercentageError Percentage -> Percentage)
-> Either MkPercentageError Percentage -> Percentage
forall a b. (a -> b) -> a -> b
$ Rational -> Either MkPercentageError Percentage
mkPercentage Rational
r
where
bomb :: Percentage
bomb = String -> Percentage
forall a. HasCallStack => String -> a
error (String -> Percentage) -> String -> Percentage
forall a b. (a -> b) -> a -> b
$ String
"unsafeMkPercentage: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Rational -> String
forall a. Show a => a -> String
show Rational
r String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is out of bounds."
unsafeIntToWord
:: forall from to
. ( HasCallStack
, Integral from
, Bounded to
, Integral to
, Typeable from
, Typeable to
, Show from)
=> from -> to
unsafeIntToWord :: from -> to
unsafeIntToWord from
n
| from
n from -> from -> Bool
forall a. Ord a => a -> a -> Bool
< to -> from
forall a b. (Integral a, Num b) => a -> b
fromIntegral (to
forall a. Bounded a => a
minBound :: to) = Builder -> to
crash Builder
"underflow"
| from
n from -> from -> Bool
forall a. Ord a => a -> a -> Bool
> to -> from
forall a b. (Integral a, Num b) => a -> b
fromIntegral (to
forall a. Bounded a => a
maxBound :: to) = Builder -> to
crash Builder
"overflow"
| Bool
otherwise = from -> to
forall a b. (Integral a, Num b) => a -> b
fromIntegral from
n
where
crash :: Builder -> to
crash :: Builder -> to
crash Builder
err = Builder -> to
forall a. HasCallStack => Builder -> a
internalError (Builder -> to) -> Builder -> to
forall a b. (a -> b) -> a -> b
$ Builder
err Builder -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+Builder
" converting value "Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+|| from
n from -> Builder -> Builder
forall a b. (Show a, FromBuilder b) => a -> Builder -> b
||+
Builder
" from " Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+|| Proxy from -> TypeRep
forall k (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy from
forall k (t :: k). Proxy t
Proxy @from) TypeRep -> Builder -> Builder
forall a b. (Show a, FromBuilder b) => a -> Builder -> b
||+
Builder
" to "Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+|| Proxy to -> TypeRep
forall k (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy to
forall k (t :: k). Proxy t
Proxy @to) TypeRep -> Builder -> Builder
forall a b. (Show a, FromBuilder b) => a -> Builder -> b
||+Builder
"!"