{-# 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
(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 Hash160
k) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x00
        Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
k
    serialize (ScriptAddress Hash160
s) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x01
        Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
s
    serialize (WitnessPubKeyAddress Hash160
h) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x02
        Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash160
h
    serialize (WitnessScriptAddress Hash256
s) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x03
        Hash256 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash256
s
    serialize (WitnessAddress Word8
v ByteString
d) = do
        Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
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
            Word8
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
            Word8
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
            Word8
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
            Word8
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
            Word8
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)
            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
$
                    Text
"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 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 = 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 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 Network
net =
    String -> (Text -> Parser Address) -> Value -> Parser Address
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"address" ((Text -> Parser Address) -> Value -> Parser Address)
-> (Text -> Parser Address) -> Value -> Parser Address
forall a b. (a -> b) -> a -> b
$ \Text
t ->
        case Network -> Text -> Maybe Address
textToAddr Network
net Text
t of
            Maybe Address
Nothing -> String -> Parser Address
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"could not decode address"
            Just 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 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 Word8
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 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 Word8
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 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 (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 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 (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 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 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 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 (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)
        Word8
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)
        Word8
_ -> Maybe Address
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) <- (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
        Word8
0 -> case ByteString -> Int
B.length ByteString
bs of
            Int
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)
            Int
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)
            Int
_ -> Maybe Address
forall a. Maybe a
Nothing
        Word8
_ -> 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 Network
net 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 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 Word8
x 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 String
"Does not recognize address prefix"

base58put :: MonadPut m => Network -> Address -> m ()
base58put :: Network -> Address -> m ()
base58put Network
net (PubKeyAddress 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 Network
net (ScriptAddress 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 Network
_ Address
_ = String -> m ()
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 (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 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 (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 String
"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 String
"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 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 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 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 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 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 Word8
v 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
        ScriptOutput
_ -> 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 TxSignature
_ 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 SimpleInput
_ 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
        ScriptInput
_ -> Maybe Address
forall a. Maybe a
Nothing