{-# 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.Crypto
import Haskoin.Data
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
        { -- | RIPEMD160 hash of public key's SHA256 hash
          Address -> Hash160
getAddrHash160 :: !Hash160
        }
    | -- | pay to script hash
      ScriptAddress
        { -- | RIPEMD160 hash of script's SHA256 hash
          getAddrHash160 :: !Hash160
        }
    | -- | pay to witness public key hash
      WitnessPubKeyAddress
        { -- | RIPEMD160 hash of public key's SHA256 hash
          getAddrHash160 :: !Hash160
        }
    | -- | pay to witness script hash
      WitnessScriptAddress
        { -- | HASH256 hash of script
          Address -> Hash256
getAddrHash256 :: !Hash256
        }
    | -- | other witness address
      WitnessAddress
        { Address -> Word8
getAddrVersion :: !Word8
        , Address -> ByteString
getAddrData :: !ByteString
        }
    deriving
        (Address -> Address -> Bool
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
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
Ord, 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
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]
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, Eq Address
Int -> Address -> Int
Address -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Address -> Int
$chash :: Address -> Int
hashWithSalt :: Int -> Address -> Int
$chashWithSalt :: Int -> Address -> Int
Hashable, Address -> ()
forall a. (a -> ()) -> NFData a
rnf :: Address -> ()
$crnf :: Address -> ()
NFData)

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

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

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

instance Binary Address where
    put :: Address -> Put
put = forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get Address
get = 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 Address
_ = Bool
False

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

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

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

addrToJSON :: Network -> Address -> Value
addrToJSON :: Network -> Address -> Value
addrToJSON Network
net Address
a = 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 Network
net = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Encoding
null_ forall a. Text -> Encoding' a
text 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 Network
net =
    forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"address" forall a b. (a -> b) -> a -> b
$ \Text
t ->
        case Network -> Text -> Maybe Address
textToAddr Network
net Text
t of
            Maybe Address
Nothing -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"could not decode address"
            Just Address
x -> 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 Network
net a :: Address
a@PubKeyAddress{getAddrHash160 :: Address -> Hash160
getAddrHash160 = Hash160
h}
    | forall a. Maybe a -> Bool
isNothing (Network -> Maybe Text
getCashAddrPrefix Network
net) =
        forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
encodeBase58Check forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). MonadPut m => Network -> Address -> m ()
base58put Network
net Address
a
    | Bool
otherwise = Network -> Word8 -> ByteString -> Maybe Text
cashAddrEncode Network
net Word8
0 (Put -> ByteString
runPutS forall a b. (a -> b) -> a -> b
$ forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h)
addrToText Network
net a :: Address
a@ScriptAddress{getAddrHash160 :: Address -> Hash160
getAddrHash160 = Hash160
h}
    | forall a. Maybe a -> Bool
isNothing (Network -> Maybe Text
getCashAddrPrefix Network
net) =
        forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
encodeBase58Check forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). MonadPut m => Network -> Address -> m ()
base58put Network
net Address
a
    | Bool
otherwise =
        Network -> Word8 -> ByteString -> Maybe Text
cashAddrEncode Network
net Word8
1 (Put -> ByteString
runPutS forall a b. (a -> b) -> a -> b
$ forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h)
addrToText 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 Word8
0 (ByteString -> Data
B.unpack (Put -> ByteString
runPutS forall a b. (a -> b) -> a -> b
$ forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h))
addrToText 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 Word8
0 (ByteString -> Data
B.unpack (Put -> ByteString
runPutS forall a b. (a -> b) -> a -> b
$ forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash256
h))
addrToText 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 Network
net Text
txt =
    Network -> Text -> Maybe Address
cashToAddr Network
net Text
txt forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Network -> Text -> Maybe Address
bech32ToAddr Network
net Text
txt 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 Network
net Text
txt = do
    (Word8
ver, ByteString
bs) <- Network -> Text -> Maybe (Word8, ByteString)
cashAddrDecode Network
net Text
txt
    case Word8
ver of
        Word8
0 -> Hash160 -> Address
PubKeyAddress forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a b. Either a b -> Maybe b
eitherToMaybe (forall a. Get a -> ByteString -> Either String a
runGetS forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize ByteString
bs)
        Word8
1 -> Hash160 -> Address
ScriptAddress forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a b. Either a b -> Maybe b
eitherToMaybe (forall a. Get a -> ByteString -> Either String a
runGetS forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize ByteString
bs)
        Word8
_ -> forall a. Maybe a
Nothing

bech32ToAddr :: Network -> Text -> Maybe Address
bech32ToAddr :: Network -> Text -> Maybe Address
bech32ToAddr Network
net Text
txt = do
    Text
hrp <- Network -> Maybe Text
getBech32Prefix Network
net
    (Word8
ver, ByteString
bs) <- forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second Data -> ByteString
B.pack 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
        Word8
0 -> case ByteString -> Int
B.length ByteString
bs of
            Int
20 -> Hash160 -> Address
WitnessPubKeyAddress forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a b. Either a b -> Maybe b
eitherToMaybe (forall a. Get a -> ByteString -> Either String a
runGetS forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize ByteString
bs)
            Int
32 -> Hash256 -> Address
WitnessScriptAddress forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a b. Either a b -> Maybe b
eitherToMaybe (forall a. Get a -> ByteString -> Either String a
runGetS forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize ByteString
bs)
            Int
_ -> forall a. Maybe a
Nothing
        Word8
_ -> forall a. a -> Maybe a
Just 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 Network
net Text
txt =
    forall a b. Either a b -> Maybe b
eitherToMaybe forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Get a -> ByteString -> Either String a
runGetS (forall (m :: * -> *). MonadGet m => Network -> m Address
base58get Network
net) 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 :: forall (m :: * -> *). MonadGet m => Network -> m Address
base58get Network
net = do
    Word8
pfx <- forall (m :: * -> *). MonadGet m => m Word8
getWord8
    Hash160
addr <- forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize
    forall {m :: * -> *}. MonadFail m => Word8 -> Hash160 -> m Address
f Word8
pfx Hash160
addr
  where
    f :: Word8 -> Hash160 -> m Address
f Word8
x Hash160
a
        | Word8
x forall a. Eq a => a -> a -> Bool
== Network -> Word8
getAddrPrefix Network
net = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
PubKeyAddress Hash160
a
        | Word8
x forall a. Eq a => a -> a -> Bool
== Network -> Word8
getScriptPrefix Network
net = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
ScriptAddress Hash160
a
        | Bool
otherwise = forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Does not recognize address prefix"

base58put :: MonadPut m => Network -> Address -> m ()
base58put :: forall (m :: * -> *). MonadPut m => Network -> Address -> m ()
base58put Network
net (PubKeyAddress Hash160
h) = do
    forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 (Network -> Word8
getAddrPrefix Network
net)
    forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h
base58put Network
net (ScriptAddress Hash160
h) = do
    forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 (Network -> Word8
getScriptPrefix Network
net)
    forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h
base58put Network
_ Address
_ = forall a. HasCallStack => String -> a
error String
"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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b. ByteArrayAccess b => b -> Hash160
addressHash forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b. ByteArrayAccess b => b -> Hash160
addressHash forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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
        forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b. ByteArrayAccess b => b -> Hash160
addressHash
        forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> ByteString
encodeOutputBS
        forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash160 -> ScriptOutput
PayWitnessPKHash
        forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b. ByteArrayAccess b => b -> Hash160
addressHash
        forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS
        forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b. ByteArrayAccess b => b -> Hash160
addressHash 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b. ByteArrayAccess b => b -> Hash256
sha256 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b. ByteArrayAccess b => b -> Hash160
addressHash forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> ByteString
encodeOutputBS forall b c a. (b -> c) -> (a -> b) -> a -> c
. Script -> ScriptOutput
toP2WSH 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 Hash160
h -> Hash160 -> ScriptOutput
PayPKHash Hash160
h
        ScriptAddress Hash160
h -> Hash160 -> ScriptOutput
PayScriptHash Hash160
h
        WitnessPubKeyAddress Hash160
h -> Hash160 -> ScriptOutput
PayWitnessPKHash Hash160
h
        WitnessScriptAddress Hash256
h -> Hash256 -> ScriptOutput
PayWitnessScriptHash Hash256
h
        WitnessAddress Word8
v 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 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize 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 =
    forall b a. b -> Maybe a -> Either b a
maybeToEither String
"Could not decode address" forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> Maybe Address
outputAddress 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 =
    forall b a. b -> Maybe a -> Either b a
maybeToEither String
"Could not decode address" forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptOutput -> Maybe Address
outputAddress 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 Hash160
h -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
PubKeyAddress Hash160
h
        PayScriptHash Hash160
h -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
ScriptAddress Hash160
h
        PayPK PubKeyI
k -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ PubKeyI -> Address
pubKeyAddr PubKeyI
k
        PayWitnessPKHash Hash160
h -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Hash160 -> Address
WitnessPubKeyAddress Hash160
h
        PayWitnessScriptHash Hash256
h -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Hash256 -> Address
WitnessScriptAddress Hash256
h
        PayWitness Word8
v ByteString
d -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Word8 -> ByteString -> Address
WitnessAddress Word8
v ByteString
d
        ScriptOutput
_ -> forall a. Maybe a
Nothing

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