{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE FlexibleContexts  #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE OverloadedStrings #-}
{-|
Module      : Haskoin.Address
Copyright   : No rights reserved
License     : MIT
Maintainer  : jprupp@protonmail.ch
Stability   : experimental
Portability : POSIX

Base58, CashAddr, Bech32 address and WIF private key serialization support.
-}
module Haskoin.Address
    ( -- * Addresses
      Address(..)
    , isPubKeyAddress
    , isScriptAddress
    , isWitnessAddress
    , isWitnessPubKeyAddress
    , isWitnessScriptAddress
    , addrToText
    , textToAddr
    , bech32ToAddr
    , cashToAddr
    , base58ToAddr
    , addrToJSON
    , addrToEncoding
    , addrFromJSON
    , pubKeyAddr
    , pubKeyWitnessAddr
    , pubKeyCompatWitnessAddr
    , p2pkhAddr
    , p2wpkhAddr
    , p2shAddr
    , p2wshAddr
    , inputAddress
    , outputAddress
    , addressToScript
    , addressToScriptBS
    , addressToOutput
    , payToScriptAddress
    , payToWitnessScriptAddress
    , payToNestedScriptAddress
    , scriptToAddress
    , scriptToAddressBS
    , module Haskoin.Address.Base58
    , module Haskoin.Address.Bech32
    , module Haskoin.Address.CashAddr
    ) where

import           Control.Applicative
import           Control.Arrow            (second)
import           Control.DeepSeq
import           Control.Monad
import           Data.Aeson               as A
import           Data.Aeson.Encoding      as A
import           Data.Aeson.Types
import           Data.Binary              (Binary (..))
import           Data.ByteString          (ByteString)
import qualified Data.ByteString          as B
import           Data.Bytes.Get
import           Data.Bytes.Put
import           Data.Bytes.Serial
import           Data.Hashable
import           Data.Maybe
import           Data.Serialize           (Serialize (..))
import           Data.Text                (Text)
import qualified Data.Text                as T
import           Data.Word                (Word8)
import           GHC.Generics             (Generic)
import           Haskoin.Address.Base58
import           Haskoin.Address.Bech32
import           Haskoin.Address.CashAddr
import           Haskoin.Constants
import           Haskoin.Crypto
import           Haskoin.Keys.Common
import           Haskoin.Script
import           Haskoin.Util

-- | Address format for Bitcoin and Bitcoin Cash.
data Address
    -- | pay to public key hash (regular)
    = PubKeyAddress
          { Address -> Hash160
getAddrHash160 :: !Hash160
          -- ^ RIPEMD160 hash of public key's SHA256 hash
          }
    -- | pay to script hash
    | ScriptAddress
          { getAddrHash160 :: !Hash160
          -- ^ RIPEMD160 hash of script's SHA256 hash
          }
    -- | pay to witness public key hash
    | WitnessPubKeyAddress
          { getAddrHash160 :: !Hash160
          -- ^ RIPEMD160 hash of public key's SHA256 hash
          }
    -- | pay to witness script hash
    | WitnessScriptAddress
          { Address -> Hash256
getAddrHash256 :: !Hash256
          -- ^ HASH256 hash of script
          }
    -- | other witness address
    | WitnessAddress
         { Address -> Word8
getAddrVersion :: !Word8
         , Address -> ByteString
getAddrData    :: !ByteString
         }
    deriving
        (Address -> Address -> Bool
(Address -> Address -> Bool)
-> (Address -> Address -> Bool) -> Eq Address
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Address -> Address -> Bool
$c/= :: Address -> Address -> Bool
== :: Address -> Address -> Bool
$c== :: Address -> Address -> Bool
Eq, Eq Address
Eq Address =>
(Address -> Address -> Ordering)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Address)
-> (Address -> Address -> Address)
-> Ord Address
Address -> Address -> Bool
Address -> Address -> Ordering
Address -> Address -> Address
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Address -> Address -> Address
$cmin :: Address -> Address -> Address
max :: Address -> Address -> Address
$cmax :: Address -> Address -> Address
>= :: Address -> Address -> Bool
$c>= :: Address -> Address -> Bool
> :: Address -> Address -> Bool
$c> :: Address -> Address -> Bool
<= :: Address -> Address -> Bool
$c<= :: Address -> Address -> Bool
< :: Address -> Address -> Bool
$c< :: Address -> Address -> Bool
compare :: Address -> Address -> Ordering
$ccompare :: Address -> Address -> Ordering
$cp1Ord :: Eq Address
Ord, (forall x. Address -> Rep Address x)
-> (forall x. Rep Address x -> Address) -> Generic Address
forall x. Rep Address x -> Address
forall x. Address -> Rep Address x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Address x -> Address
$cfrom :: forall x. Address -> Rep Address x
Generic, Int -> Address -> ShowS
[Address] -> ShowS
Address -> String
(Int -> Address -> ShowS)
-> (Address -> String) -> ([Address] -> ShowS) -> Show Address
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Address] -> ShowS
$cshowList :: [Address] -> ShowS
show :: Address -> String
$cshow :: Address -> String
showsPrec :: Int -> Address -> ShowS
$cshowsPrec :: Int -> Address -> ShowS
Show, ReadPrec [Address]
ReadPrec Address
Int -> ReadS Address
ReadS [Address]
(Int -> ReadS Address)
-> ReadS [Address]
-> ReadPrec Address
-> ReadPrec [Address]
-> Read Address
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Address]
$creadListPrec :: ReadPrec [Address]
readPrec :: ReadPrec Address
$creadPrec :: ReadPrec Address
readList :: ReadS [Address]
$creadList :: ReadS [Address]
readsPrec :: Int -> ReadS Address
$creadsPrec :: Int -> ReadS Address
Read, Int -> Address -> Int
Address -> Int
(Int -> Address -> Int) -> (Address -> Int) -> Hashable Address
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Address -> Int
$chash :: Address -> Int
hashWithSalt :: Int -> Address -> Int
$chashWithSalt :: Int -> Address -> Int
Hashable, Address -> ()
(Address -> ()) -> NFData Address
forall a. (a -> ()) -> NFData a
rnf :: Address -> ()
$crnf :: Address -> ()
NFData)

instance Serial Address where
    serialize :: Address -> m ()
serialize (PubKeyAddress k :: Hash160
k) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x00
        Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
k
    serialize (ScriptAddress s :: Hash160
s) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x01
        Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
s
    serialize (WitnessPubKeyAddress h :: Hash160
h) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x02
        Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h
    serialize (WitnessScriptAddress s :: Hash256
s) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x03
        Hash256 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash256
s
    serialize (WitnessAddress v :: Word8
v d :: ByteString
d) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x04
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
v
        Word64 -> m ()
forall (m :: * -> *). MonadPut m => Word64 -> m ()
putWord64be (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
B.length ByteString
d))
        ByteString -> m ()
forall (m :: * -> *). MonadPut m => ByteString -> m ()
putByteString ByteString
d

    deserialize :: m Address
deserialize =
        m Word8
forall (m :: * -> *). MonadGet m => m Word8
getWord8 m Word8 -> (Word8 -> m Address) -> m Address
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        0x00 -> Hash160 -> Address
PubKeyAddress (Hash160 -> Address) -> m Hash160 -> m Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Hash160
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize
        0x01 -> Hash160 -> Address
ScriptAddress (Hash160 -> Address) -> m Hash160 -> m Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Hash160
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize
        0x02 -> Hash160 -> Address
WitnessPubKeyAddress (Hash160 -> Address) -> m Hash160 -> m Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Hash160
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize
        0x03 -> Hash256 -> Address
WitnessScriptAddress (Hash256 -> Address) -> m Hash256 -> m Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Hash256
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize
        0x04 -> Word8 -> ByteString -> Address
WitnessAddress (Word8 -> ByteString -> Address)
-> m Word8 -> m (ByteString -> Address)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Word8
forall (m :: * -> *). MonadGet m => m Word8
getWord8 m (ByteString -> Address) -> m ByteString -> m Address
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>
                (Int -> m ByteString
forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (Int -> m ByteString) -> (Word64 -> Int) -> Word64 -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> m ByteString) -> m Word64 -> m ByteString
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m Word64
forall (m :: * -> *). MonadGet m => m Word64
getWord64be)
        b :: Word8
b -> String -> m Address
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> m Address) -> (Text -> String) -> Text -> m Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack (Text -> m Address) -> Text -> m Address
forall a b. (a -> b) -> a -> b
$
             "Could not decode address type byte: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
             ByteString -> Text
encodeHex (Word8 -> ByteString
B.singleton Word8
b)

instance Serialize Address where
    put :: Putter Address
put = Putter Address
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get Address
get = Get Address
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize

instance Binary Address where
    put :: Address -> Put
put = Address -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get Address
get = Get Address
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize

-- | 'Address' pays to a public key hash.
isPubKeyAddress :: Address -> Bool
isPubKeyAddress :: Address -> Bool
isPubKeyAddress PubKeyAddress {} = Bool
True
isPubKeyAddress _                = Bool
False

-- | 'Address' pays to a script hash.
isScriptAddress :: Address -> Bool
isScriptAddress :: Address -> Bool
isScriptAddress ScriptAddress {} = Bool
True
isScriptAddress _                = Bool
False

-- | 'Address' pays to a witness public key hash. Only valid for SegWit
-- networks.
isWitnessPubKeyAddress :: Address -> Bool
isWitnessPubKeyAddress :: Address -> Bool
isWitnessPubKeyAddress WitnessPubKeyAddress {} = Bool
True
isWitnessPubKeyAddress _                       = Bool
False

isWitnessScriptAddress :: Address -> Bool
isWitnessScriptAddress :: Address -> Bool
isWitnessScriptAddress WitnessScriptAddress {} = Bool
True
isWitnessScriptAddress _                       = Bool
False

isWitnessAddress :: Address -> Bool
isWitnessAddress :: Address -> Bool
isWitnessAddress WitnessAddress {} = Bool
True
isWitnessAddress _                 = Bool
False

addrToJSON :: Network -> Address -> Value
addrToJSON :: Network -> Address -> Value
addrToJSON net :: Network
net a :: Address
a = Maybe Text -> Value
forall a. ToJSON a => a -> Value
toJSON (Network -> Address -> Maybe Text
addrToText Network
net Address
a)

addrToEncoding :: Network -> Address -> Encoding
addrToEncoding :: Network -> Address -> Encoding
addrToEncoding net :: Network
net = Encoding -> (Text -> Encoding) -> Maybe Text -> Encoding
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Encoding
null_ Text -> Encoding
forall a. Text -> Encoding' a
text (Maybe Text -> Encoding)
-> (Address -> Maybe Text) -> Address -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Network -> Address -> Maybe Text
addrToText Network
net

-- | JSON parsing for Bitcoin addresses. Works with 'Base58', 'CashAddr' and
-- 'Bech32'.
addrFromJSON :: Network -> Value -> Parser Address
addrFromJSON :: Network -> Value -> Parser Address
addrFromJSON net :: Network
net =
    String -> (Text -> Parser Address) -> Value -> Parser Address
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText "address" ((Text -> Parser Address) -> Value -> Parser Address)
-> (Text -> Parser Address) -> Value -> Parser Address
forall a b. (a -> b) -> a -> b
$ \t :: Text
t ->
        case Network -> Text -> Maybe Address
textToAddr Network
net Text
t of
            Nothing -> String -> Parser Address
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "could not decode address"
            Just x :: Address
x  -> Address -> Parser Address
forall (m :: * -> *) a. Monad m => a -> m a
return Address
x

-- | Convert address to human-readable string. Uses 'Base58', 'Bech32', or
-- 'CashAddr' depending on network.
addrToText :: Network -> Address -> Maybe Text
addrToText :: Network -> Address -> Maybe Text
addrToText net :: Network
net a :: Address
a@PubKeyAddress {getAddrHash160 :: Address -> Hash160
getAddrHash160 = Hash160
h}
    | Maybe Text -> Bool
forall a. Maybe a -> Bool
isNothing (Network -> Maybe Text
getCashAddrPrefix Network
net) =
        Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> (Put -> Text) -> Put -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
encodeBase58Check (ByteString -> Text) -> (Put -> ByteString) -> Put -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS (Put -> Maybe Text) -> Put -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Network -> Putter Address
forall (m :: * -> *). MonadPut m => Network -> Address -> m ()
base58put Network
net Address
a
    | Bool
otherwise = Network -> Word8 -> ByteString -> Maybe Text
cashAddrEncode Network
net 0 (Put -> ByteString
runPutS (Put -> ByteString) -> Put -> ByteString
forall a b. (a -> b) -> a -> b
$ Hash160 -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h)
addrToText net :: Network
net a :: Address
a@ScriptAddress {getAddrHash160 :: Address -> Hash160
getAddrHash160 = Hash160
h}
    | Maybe Text -> Bool
forall a. Maybe a -> Bool
isNothing (Network -> Maybe Text
getCashAddrPrefix Network
net) =
        Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> (Put -> Text) -> Put -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
encodeBase58Check (ByteString -> Text) -> (Put -> ByteString) -> Put -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS (Put -> Maybe Text) -> Put -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Network -> Putter Address
forall (m :: * -> *). MonadPut m => Network -> Address -> m ()
base58put Network
net Address
a
    | Bool
otherwise =
        Network -> Word8 -> ByteString -> Maybe Text
cashAddrEncode Network
net 1 (Put -> ByteString
runPutS (Put -> ByteString) -> Put -> ByteString
forall a b. (a -> b) -> a -> b
$ Hash160 -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h)
addrToText net :: Network
net WitnessPubKeyAddress {getAddrHash160 :: Address -> Hash160
getAddrHash160 = Hash160
h} = do
    Text
hrp <- Network -> Maybe Text
getBech32Prefix Network
net
    Text -> Word8 -> Data -> Maybe Text
segwitEncode Text
hrp 0 (ByteString -> Data
B.unpack (Put -> ByteString
runPutS (Put -> ByteString) -> Put -> ByteString
forall a b. (a -> b) -> a -> b
$ Hash160 -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h))
addrToText net :: Network
net WitnessScriptAddress {getAddrHash256 :: Address -> Hash256
getAddrHash256 = Hash256
h} = do
    Text
hrp <- Network -> Maybe Text
getBech32Prefix Network
net
    Text -> Word8 -> Data -> Maybe Text
segwitEncode Text
hrp 0 (ByteString -> Data
B.unpack (Put -> ByteString
runPutS (Put -> ByteString) -> Put -> ByteString
forall a b. (a -> b) -> a -> b
$ Hash256 -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash256
h))
addrToText net :: Network
net WitnessAddress {getAddrVersion :: Address -> Word8
getAddrVersion = Word8
v, getAddrData :: Address -> ByteString
getAddrData = ByteString
d} = do
    Text
hrp <- Network -> Maybe Text
getBech32Prefix Network
net
    Text -> Word8 -> Data -> Maybe Text
segwitEncode Text
hrp Word8
v (ByteString -> Data
B.unpack ByteString
d)

-- | Parse 'Base58', 'Bech32' or 'CashAddr' address, depending on network.
textToAddr :: Network -> Text -> Maybe Address
textToAddr :: Network -> Text -> Maybe Address
textToAddr net :: Network
net txt :: Text
txt =
    Network -> Text -> Maybe Address
cashToAddr Network
net Text
txt Maybe Address -> Maybe Address -> Maybe Address
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Network -> Text -> Maybe Address
bech32ToAddr Network
net Text
txt Maybe Address -> Maybe Address -> Maybe Address
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Network -> Text -> Maybe Address
base58ToAddr Network
net Text
txt

cashToAddr :: Network -> Text -> Maybe Address
cashToAddr :: Network -> Text -> Maybe Address
cashToAddr net :: Network
net txt :: Text
txt = do
    (ver :: Word8
ver, bs :: ByteString
bs) <- Network -> Text -> Maybe (Word8, ByteString)
cashAddrDecode Network
net Text
txt
    case Word8
ver of
        0 -> Hash160 -> Address
PubKeyAddress (Hash160 -> Address) -> Maybe Hash160 -> Maybe Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either String Hash160 -> Maybe Hash160
forall a b. Either a b -> Maybe b
eitherToMaybe (Get Hash160 -> ByteString -> Either String Hash160
forall a. Get a -> ByteString -> Either String a
runGetS Get Hash160
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize ByteString
bs)
        1 -> Hash160 -> Address
ScriptAddress (Hash160 -> Address) -> Maybe Hash160 -> Maybe Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either String Hash160 -> Maybe Hash160
forall a b. Either a b -> Maybe b
eitherToMaybe (Get Hash160 -> ByteString -> Either String Hash160
forall a. Get a -> ByteString -> Either String a
runGetS Get Hash160
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize ByteString
bs)
        _ -> Maybe Address
forall a. Maybe a
Nothing

bech32ToAddr :: Network -> Text -> Maybe Address
bech32ToAddr :: Network -> Text -> Maybe Address
bech32ToAddr net :: Network
net txt :: Text
txt = do
    Text
hrp <- Network -> Maybe Text
getBech32Prefix Network
net
    (ver :: Word8
ver, bs :: ByteString
bs) <- (Data -> ByteString) -> (Word8, Data) -> (Word8, ByteString)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second Data -> ByteString
B.pack ((Word8, Data) -> (Word8, ByteString))
-> Maybe (Word8, Data) -> Maybe (Word8, ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Text -> Maybe (Word8, Data)
segwitDecode Text
hrp Text
txt
    case Word8
ver of
        0 -> case ByteString -> Int
B.length ByteString
bs of
            20 -> Hash160 -> Address
WitnessPubKeyAddress (Hash160 -> Address) -> Maybe Hash160 -> Maybe Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either String Hash160 -> Maybe Hash160
forall a b. Either a b -> Maybe b
eitherToMaybe (Get Hash160 -> ByteString -> Either String Hash160
forall a. Get a -> ByteString -> Either String a
runGetS Get Hash160
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize ByteString
bs)
            32 -> Hash256 -> Address
WitnessScriptAddress (Hash256 -> Address) -> Maybe Hash256 -> Maybe Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either String Hash256 -> Maybe Hash256
forall a b. Either a b -> Maybe b
eitherToMaybe (Get Hash256 -> ByteString -> Either String Hash256
forall a. Get a -> ByteString -> Either String a
runGetS Get Hash256
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize ByteString
bs)
            _  -> Maybe Address
forall a. Maybe a
Nothing
        _ -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ Word8 -> ByteString -> Address
WitnessAddress Word8
ver ByteString
bs

base58ToAddr :: Network -> Text -> Maybe Address
base58ToAddr :: Network -> Text -> Maybe Address
base58ToAddr net :: Network
net txt :: Text
txt =
    Either String Address -> Maybe Address
forall a b. Either a b -> Maybe b
eitherToMaybe (Either String Address -> Maybe Address)
-> (ByteString -> Either String Address)
-> ByteString
-> Maybe Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Get Address -> ByteString -> Either String Address
forall a. Get a -> ByteString -> Either String a
runGetS (Network -> Get Address
forall (m :: * -> *). MonadGet m => Network -> m Address
base58get Network
net) (ByteString -> Maybe Address) -> Maybe ByteString -> Maybe Address
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Text -> Maybe ByteString
decodeBase58Check Text
txt

base58get :: MonadGet m => Network -> m Address
base58get :: Network -> m Address
base58get net :: Network
net = do
    Word8
pfx <- m Word8
forall (m :: * -> *). MonadGet m => m Word8
getWord8
    Hash160
addr <- m Hash160
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize
    Word8 -> Hash160 -> m Address
forall (m :: * -> *). MonadFail m => Word8 -> Hash160 -> m Address
f Word8
pfx Hash160
addr
  where
    f :: Word8 -> Hash160 -> m Address
f x :: Word8
x a :: Hash160
a
        | Word8
x Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Network -> Word8
getAddrPrefix Network
net = Address -> m Address
forall (m :: * -> *) a. Monad m => a -> m a
return (Address -> m Address) -> Address -> m Address
forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
PubKeyAddress Hash160
a
        | Word8
x Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Network -> Word8
getScriptPrefix Network
net = Address -> m Address
forall (m :: * -> *) a. Monad m => a -> m a
return (Address -> m Address) -> Address -> m Address
forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
ScriptAddress Hash160
a
        | Bool
otherwise = String -> m Address
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "Does not recognize address prefix"

base58put :: MonadPut m => Network -> Address -> m ()
base58put :: Network -> Address -> m ()
base58put net :: Network
net (PubKeyAddress h :: Hash160
h) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 (Network -> Word8
getAddrPrefix Network
net)
        Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h
base58put net :: Network
net (ScriptAddress h :: Hash160
h) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 (Network -> Word8
getScriptPrefix Network
net)
        Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h
base58put _ _ = String -> m ()
forall a. HasCallStack => String -> a
error "Cannot serialize this address as Base58"

-- | Obtain a standard pay-to-public-key-hash address from a public key.
pubKeyAddr :: PubKeyI -> Address
pubKeyAddr :: PubKeyI -> Address
pubKeyAddr = Hash160 -> Address
PubKeyAddress (Hash160 -> Address) -> (PubKeyI -> Hash160) -> PubKeyI -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash (ByteString -> Hash160)
-> (PubKeyI -> ByteString) -> PubKeyI -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS (Put -> ByteString) -> (PubKeyI -> Put) -> PubKeyI -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PubKeyI -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize

-- | Obtain a standard pay-to-public-key-hash (P2PKH) address from a 'Hash160'.
p2pkhAddr :: Hash160 -> Address
p2pkhAddr :: Hash160 -> Address
p2pkhAddr = Hash160 -> Address
PubKeyAddress

-- | Obtain a SegWit pay-to-witness-public-key-hash (P2WPKH) address from a
-- public key.
pubKeyWitnessAddr :: PubKeyI -> Address
pubKeyWitnessAddr :: PubKeyI -> Address
pubKeyWitnessAddr = Hash160 -> Address
WitnessPubKeyAddress (Hash160 -> Address) -> (PubKeyI -> Hash160) -> PubKeyI -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash (ByteString -> Hash160)
-> (PubKeyI -> ByteString) -> PubKeyI -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS (Put -> ByteString) -> (PubKeyI -> Put) -> PubKeyI -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PubKeyI -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize

-- | Obtain a backwards-compatible SegWit P2SH-P2WPKH address from a public key.
pubKeyCompatWitnessAddr :: PubKeyI -> Address
pubKeyCompatWitnessAddr :: PubKeyI -> Address
pubKeyCompatWitnessAddr =
    Hash160 -> Address
p2shAddr (Hash160 -> Address) -> (PubKeyI -> Hash160) -> PubKeyI -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash (ByteString -> Hash160)
-> (PubKeyI -> ByteString) -> PubKeyI -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    ScriptOutput -> ByteString
encodeOutputBS (ScriptOutput -> ByteString)
-> (PubKeyI -> ScriptOutput) -> PubKeyI -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Hash160 -> ScriptOutput
PayWitnessPKHash (Hash160 -> ScriptOutput)
-> (PubKeyI -> Hash160) -> PubKeyI -> ScriptOutput
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash (ByteString -> Hash160)
-> (PubKeyI -> ByteString) -> PubKeyI -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Put -> ByteString
runPutS (Put -> ByteString) -> (PubKeyI -> Put) -> PubKeyI -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    PubKeyI -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize

-- | Obtain a SegWit pay-to-witness-public-key-hash (P2WPKH) address from a
-- 'Hash160'.
p2wpkhAddr :: Hash160 -> Address
p2wpkhAddr :: Hash160 -> Address
p2wpkhAddr = Hash160 -> Address
WitnessPubKeyAddress

-- | Obtain a standard pay-to-script-hash (P2SH) address from a 'Hash160'.
p2shAddr :: Hash160 -> Address
p2shAddr :: Hash160 -> Address
p2shAddr = Hash160 -> Address
ScriptAddress

-- | Obtain a SegWit pay-to-witness-script-hash (P2WSH) address from a 'Hash256'
p2wshAddr :: Hash256 -> Address
p2wshAddr :: Hash256 -> Address
p2wshAddr = Hash256 -> Address
WitnessScriptAddress

-- | Compute a standard pay-to-script-hash (P2SH) address for an output script.
payToScriptAddress :: ScriptOutput -> Address
payToScriptAddress :: ScriptOutput -> Address
payToScriptAddress = Hash160 -> Address
p2shAddr (Hash160 -> Address)
-> (ScriptOutput -> Hash160) -> ScriptOutput -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash (ByteString -> Hash160)
-> (ScriptOutput -> ByteString) -> ScriptOutput -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> ByteString
encodeOutputBS

-- | Compute a SegWit pay-to-witness-script-hash (P2WSH) address for an output
-- script.
payToWitnessScriptAddress :: ScriptOutput -> Address
payToWitnessScriptAddress :: ScriptOutput -> Address
payToWitnessScriptAddress = Hash256 -> Address
p2wshAddr (Hash256 -> Address)
-> (ScriptOutput -> Hash256) -> ScriptOutput -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Hash256
forall b. ByteArrayAccess b => b -> Hash256
sha256 (ByteString -> Hash256)
-> (ScriptOutput -> ByteString) -> ScriptOutput -> Hash256
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> ByteString
encodeOutputBS

-- | Compute a backwards-compatible SegWit P2SH-P2WSH address.
payToNestedScriptAddress :: ScriptOutput -> Address
payToNestedScriptAddress :: ScriptOutput -> Address
payToNestedScriptAddress =
    Hash160 -> Address
p2shAddr (Hash160 -> Address)
-> (ScriptOutput -> Hash160) -> ScriptOutput -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash (ByteString -> Hash160)
-> (ScriptOutput -> ByteString) -> ScriptOutput -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> ByteString
encodeOutputBS (ScriptOutput -> ByteString)
-> (ScriptOutput -> ScriptOutput) -> ScriptOutput -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Script -> ScriptOutput
toP2WSH (Script -> ScriptOutput)
-> (ScriptOutput -> Script) -> ScriptOutput -> ScriptOutput
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> Script
encodeOutput

-- | Encode an output script from an address. Will fail if using a
-- pay-to-witness address on a non-SegWit network.
addressToOutput :: Address -> ScriptOutput
addressToOutput :: Address -> ScriptOutput
addressToOutput =
    \case
        PubKeyAddress h :: Hash160
h        -> Hash160 -> ScriptOutput
PayPKHash Hash160
h
        ScriptAddress h :: Hash160
h        -> Hash160 -> ScriptOutput
PayScriptHash Hash160
h
        WitnessPubKeyAddress h :: Hash160
h -> Hash160 -> ScriptOutput
PayWitnessPKHash Hash160
h
        WitnessScriptAddress h :: Hash256
h -> Hash256 -> ScriptOutput
PayWitnessScriptHash Hash256
h
        WitnessAddress v :: Word8
v d :: ByteString
d     -> Word8 -> ByteString -> ScriptOutput
PayWitness Word8
v ByteString
d

-- | Get output script AST for an 'Address'.
addressToScript :: Address -> Script
addressToScript :: Address -> Script
addressToScript = ScriptOutput -> Script
encodeOutput (ScriptOutput -> Script)
-> (Address -> ScriptOutput) -> Address -> Script
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Address -> ScriptOutput
addressToOutput

-- | Encode address as output script in 'ByteString' form.
addressToScriptBS :: Address -> ByteString
addressToScriptBS :: Address -> ByteString
addressToScriptBS = Put -> ByteString
runPutS (Put -> ByteString) -> Putter Address -> Address -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Script -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize (Script -> Put) -> (Address -> Script) -> Putter Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Address -> Script
addressToScript

-- | Decode an output script into an 'Address' if it has such representation.
scriptToAddress :: Script -> Either String Address
scriptToAddress :: Script -> Either String Address
scriptToAddress =
    String -> Maybe Address -> Either String Address
forall b a. b -> Maybe a -> Either b a
maybeToEither "Could not decode address" (Maybe Address -> Either String Address)
-> (ScriptOutput -> Maybe Address)
-> ScriptOutput
-> Either String Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> Maybe Address
outputAddress (ScriptOutput -> Either String Address)
-> (Script -> Either String ScriptOutput)
-> Script
-> Either String Address
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< Script -> Either String ScriptOutput
decodeOutput

-- | Decode a serialized script into an 'Address'.
scriptToAddressBS :: ByteString -> Either String Address
scriptToAddressBS :: ByteString -> Either String Address
scriptToAddressBS =
    String -> Maybe Address -> Either String Address
forall b a. b -> Maybe a -> Either b a
maybeToEither "Could not decode address" (Maybe Address -> Either String Address)
-> (ScriptOutput -> Maybe Address)
-> ScriptOutput
-> Either String Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> Maybe Address
outputAddress (ScriptOutput -> Either String Address)
-> (ByteString -> Either String ScriptOutput)
-> ByteString
-> Either String Address
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< ByteString -> Either String ScriptOutput
decodeOutputBS

-- | Get the 'Address' of a 'ScriptOutput'.
outputAddress :: ScriptOutput -> Maybe Address
outputAddress :: ScriptOutput -> Maybe Address
outputAddress =
    \case
        PayPKHash h :: Hash160
h            -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
PubKeyAddress Hash160
h
        PayScriptHash h :: Hash160
h        -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
ScriptAddress Hash160
h
        PayPK k :: PubKeyI
k                -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ PubKeyI -> Address
pubKeyAddr PubKeyI
k
        PayWitnessPKHash h :: Hash160
h     -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
WitnessPubKeyAddress Hash160
h
        PayWitnessScriptHash h :: Hash256
h -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ Hash256 -> Address
WitnessScriptAddress Hash256
h
        PayWitness v :: Word8
v d :: ByteString
d         -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ Word8 -> ByteString -> Address
WitnessAddress Word8
v ByteString
d
        _                      -> Maybe Address
forall a. Maybe a
Nothing

-- | Infer the 'Address' of a 'ScriptInput'.
inputAddress :: ScriptInput -> Maybe Address
inputAddress :: ScriptInput -> Maybe Address
inputAddress =
    \case
        (RegularInput (SpendPKHash _ key :: PubKeyI
key)) -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ PubKeyI -> Address
pubKeyAddr PubKeyI
key
        (ScriptHashInput _ rdm :: ScriptOutput
rdm)            -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ ScriptOutput -> Address
payToScriptAddress ScriptOutput
rdm
        _                                  -> Maybe Address
forall a. Maybe a
Nothing