{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoFieldSelectors #-}

-- |
-- 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,
    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 (Alternative ((<|>)))
import Control.Arrow (second)
import Control.DeepSeq (NFData)
import Control.Monad ((<=<))
import Crypto.Secp256k1
import Data.Aeson (ToJSON (toJSON), Value, withText)
import Data.Aeson.Encoding (Encoding, null_, text)
import Data.Aeson.Types (Encoding, Parser, ToJSON (toJSON), Value, withText)
import Data.Binary (Binary (..))
import Data.ByteString (ByteString)
import Data.ByteString qualified as B
import Data.Bytes.Get (MonadGet (getByteString, getWord64be, getWord8), runGetS)
import Data.Bytes.Put (MonadPut (putByteString, putWord64be, putWord8), runPutS)
import Data.Bytes.Serial (Serial (..))
import Data.Hashable (Hashable)
import Data.Maybe (isNothing)
import Data.Serialize (Serialize (..))
import Data.Text (Text)
import Data.Text qualified 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.Hash
import Haskoin.Crypto.Keys.Common
import Haskoin.Network.Data
import Haskoin.Script.Common
import Haskoin.Script.Standard
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
hash160 :: !Hash160
      }
  | -- | pay to script hash
    ScriptAddress
      { -- | RIPEMD160 hash of script's SHA256 hash
        hash160 :: !Hash160
      }
  | -- | pay to witness public key hash
    WitnessPubKeyAddress
      { -- | RIPEMD160 hash of public key's SHA256 hash
        hash160 :: !Hash160
      }
  | -- | pay to witness script hash
    WitnessScriptAddress
      { -- | HASH256 hash of script
        Address -> Hash256
hash256 :: !Hash256
      }
  | -- | other witness address
    WitnessAddress
      { Address -> Word8
version :: !Word8,
        Address -> ByteString
bytes :: !ByteString
      }
  deriving
    (Address -> Address -> Bool
(Address -> Address -> Bool)
-> (Address -> Address -> Bool) -> Eq Address
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Address -> Address -> Bool
== :: Address -> Address -> Bool
$c/= :: Address -> Address -> Bool
/= :: 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
$ccompare :: Address -> Address -> Ordering
compare :: Address -> Address -> Ordering
$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
>= :: Address -> Address -> Bool
$cmax :: Address -> Address -> Address
max :: Address -> Address -> Address
$cmin :: Address -> Address -> Address
min :: Address -> Address -> 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
$cfrom :: forall x. Address -> Rep Address x
from :: forall x. Address -> Rep Address x
$cto :: forall x. Rep Address x -> Address
to :: forall x. Rep Address x -> Address
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
$cshowsPrec :: Int -> Address -> ShowS
showsPrec :: Int -> Address -> ShowS
$cshow :: Address -> String
show :: Address -> String
$cshowList :: [Address] -> ShowS
showList :: [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
$creadsPrec :: Int -> ReadS Address
readsPrec :: Int -> ReadS Address
$creadList :: ReadS [Address]
readList :: ReadS [Address]
$creadPrec :: ReadPrec Address
readPrec :: ReadPrec Address
$creadListPrec :: ReadPrec [Address]
readListPrec :: ReadPrec [Address]
Read, Eq Address
Eq Address =>
(Int -> Address -> Int) -> (Address -> Int) -> Hashable Address
Int -> Address -> Int
Address -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> Address -> Int
hashWithSalt :: Int -> Address -> Int
$chash :: Address -> Int
hash :: Address -> Int
Hashable, Address -> ()
(Address -> ()) -> NFData Address
forall a. (a -> ()) -> NFData a
$crnf :: Address -> ()
rnf :: Address -> ()
NFData)

instance Serial Address where
  serialize :: forall (m :: * -> *). MonadPut m => 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 ()
forall (m :: * -> *). MonadPut m => Hash160 -> 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 ()
forall (m :: * -> *). MonadPut m => Hash160 -> 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 ()
forall (m :: * -> *). MonadPut m => Hash160 -> 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 ()
forall (m :: * -> *). MonadPut m => Hash256 -> 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 :: forall (m :: * -> *). MonadGet m => m Address
deserialize =
    m Word8
forall (m :: * -> *). MonadGet m => m Word8
getWord8 m Word8 -> (Word8 -> m Address) -> m Address
forall a b. m a -> (a -> m b) -> m b
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
forall (m :: * -> *). MonadGet m => m Hash160
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
forall (m :: * -> *). MonadGet m => m Hash160
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
forall (m :: * -> *). MonadGet m => m Hash160
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
forall (m :: * -> *). MonadGet m => m Hash256
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 a b. m (a -> b) -> m a -> m b
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 a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> m Address) -> (HRP -> String) -> HRP -> m Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HRP -> String
T.unpack (HRP -> m Address) -> HRP -> m Address
forall a b. (a -> b) -> a -> b
$
          HRP
"Could not decode address type byte: "
            HRP -> HRP -> HRP
forall a. Semigroup a => a -> a -> a
<> ByteString -> HRP
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 ()
forall (m :: * -> *). MonadPut m => Address -> m ()
serialize
  get :: Get Address
get = Get Address
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
forall (m :: * -> *). MonadGet m => m Address
deserialize

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

instance MarshalJSON Network Address where
  marshalValue :: Network -> Address -> Value
marshalValue Network
net Address
a = Maybe HRP -> Value
forall a. ToJSON a => a -> Value
toJSON (Network -> Address -> Maybe HRP
addrToText Network
net Address
a)
  marshalEncoding :: Network -> Address -> Encoding
marshalEncoding Network
net = Encoding -> (HRP -> Encoding) -> Maybe HRP -> Encoding
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Encoding
null_ HRP -> Encoding
forall a. HRP -> Encoding' a
text (Maybe HRP -> Encoding)
-> (Address -> Maybe HRP) -> Address -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Network -> Address -> Maybe HRP
addrToText Network
net
  unmarshalValue :: Network -> Value -> Parser Address
unmarshalValue Network
net =
    String -> (HRP -> Parser Address) -> Value -> Parser Address
forall a. String -> (HRP -> Parser a) -> Value -> Parser a
withText String
"address" ((HRP -> Parser Address) -> Value -> Parser Address)
-> (HRP -> Parser Address) -> Value -> Parser Address
forall a b. (a -> b) -> a -> b
$ \HRP
t ->
      case Network -> HRP -> Maybe Address
textToAddr Network
net HRP
t of
        Maybe Address
Nothing -> String -> Parser Address
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"could not decode address"
        Just Address
x -> Address -> Parser Address
forall a. a -> Parser a
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 HRP
addrToText Network
net a :: Address
a@PubKeyAddress {$sel:hash160:PubKeyAddress :: Address -> Hash160
hash160 = Hash160
h}
  | Maybe HRP -> Bool
forall a. Maybe a -> Bool
isNothing Network
net.cashAddrPrefix =
      HRP -> Maybe HRP
forall a. a -> Maybe a
Just (HRP -> Maybe HRP) -> (Put -> HRP) -> Put -> Maybe HRP
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> HRP
encodeBase58Check (ByteString -> HRP) -> (Put -> ByteString) -> Put -> HRP
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS (Put -> Maybe HRP) -> Put -> Maybe HRP
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 HRP
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 ()
forall (m :: * -> *). MonadPut m => Hash160 -> m ()
serialize Hash160
h)
addrToText Network
net a :: Address
a@ScriptAddress {$sel:hash160:PubKeyAddress :: Address -> Hash160
hash160 = Hash160
h}
  | Maybe HRP -> Bool
forall a. Maybe a -> Bool
isNothing Network
net.cashAddrPrefix =
      HRP -> Maybe HRP
forall a. a -> Maybe a
Just (HRP -> Maybe HRP) -> (Put -> HRP) -> Put -> Maybe HRP
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> HRP
encodeBase58Check (ByteString -> HRP) -> (Put -> ByteString) -> Put -> HRP
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS (Put -> Maybe HRP) -> Put -> Maybe HRP
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 HRP
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 ()
forall (m :: * -> *). MonadPut m => Hash160 -> m ()
serialize Hash160
h)
addrToText Network
net WitnessPubKeyAddress {$sel:hash160:PubKeyAddress :: Address -> Hash160
hash160 = Hash160
h} = do
  HRP
hrp <- Network
net.bech32Prefix
  HRP -> Word8 -> Data -> Maybe HRP
segwitEncode HRP
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 ()
forall (m :: * -> *). MonadPut m => Hash160 -> m ()
serialize Hash160
h))
addrToText Network
net WitnessScriptAddress {$sel:hash256:PubKeyAddress :: Address -> Hash256
hash256 = Hash256
h} = do
  HRP
hrp <- Network
net.bech32Prefix
  HRP -> Word8 -> Data -> Maybe HRP
segwitEncode HRP
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 ()
forall (m :: * -> *). MonadPut m => Hash256 -> m ()
serialize Hash256
h))
addrToText Network
net WitnessAddress {$sel:version:PubKeyAddress :: Address -> Word8
version = Word8
v, $sel:bytes:PubKeyAddress :: Address -> ByteString
bytes = ByteString
d} = do
  HRP
hrp <- Network
net.bech32Prefix
  HRP -> Word8 -> Data -> Maybe HRP
segwitEncode HRP
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 -> HRP -> Maybe Address
textToAddr Network
net HRP
txt =
  Network -> HRP -> Maybe Address
cashToAddr Network
net HRP
txt Maybe Address -> Maybe Address -> Maybe Address
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Network -> HRP -> Maybe Address
bech32ToAddr Network
net HRP
txt Maybe Address -> Maybe Address -> Maybe Address
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Network -> HRP -> Maybe Address
base58ToAddr Network
net HRP
txt

cashToAddr :: Network -> Text -> Maybe Address
cashToAddr :: Network -> HRP -> Maybe Address
cashToAddr Network
net HRP
txt = do
  (Word8
ver, ByteString
bs) <- Network -> HRP -> Maybe (Word8, ByteString)
cashAddrDecode Network
net HRP
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
forall (m :: * -> *). MonadGet m => m Hash160
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
forall (m :: * -> *). MonadGet m => m Hash160
deserialize ByteString
bs)
    Word8
_ -> Maybe Address
forall a. Maybe a
Nothing

bech32ToAddr :: Network -> Text -> Maybe Address
bech32ToAddr :: Network -> HRP -> Maybe Address
bech32ToAddr Network
net HRP
txt = do
  HRP
hrp <- Network
net.bech32Prefix
  (Word8
ver, ByteString
bs) <- (Data -> ByteString) -> (Word8, Data) -> (Word8, ByteString)
forall b c d. (b -> c) -> (d, b) -> (d, c)
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
<$> HRP -> HRP -> Maybe (Word8, Data)
segwitDecode HRP
hrp HRP
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
forall (m :: * -> *). MonadGet m => m Hash160
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
forall (m :: * -> *). MonadGet m => m Hash256
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 -> HRP -> Maybe Address
base58ToAddr Network
net HRP
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
=<< HRP -> Maybe ByteString
decodeBase58Check HRP
txt

base58get :: (MonadGet m) => Network -> m Address
base58get :: forall (m :: * -> *). MonadGet m => 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
forall (m :: * -> *). MonadGet m => m Hash160
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
net.addrPrefix = Address -> m Address
forall a. a -> m a
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
net.scriptPrefix = Address -> m Address
forall a. a -> m a
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 a. String -> m a
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
  Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Network
net.addrPrefix
  Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
forall (m :: * -> *). MonadPut m => Hash160 -> m ()
serialize Hash160
h
base58put Network
net (ScriptAddress Hash160
h) = do
  Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Network
net.scriptPrefix
  Hash160 -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
forall (m :: * -> *). MonadPut m => Hash160 -> 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 :: Ctx -> PublicKey -> Address
pubKeyAddr :: Ctx -> PublicKey -> Address
pubKeyAddr Ctx
ctx = Hash160 -> Address
PubKeyAddress (Hash160 -> Address)
-> (PublicKey -> Hash160) -> PublicKey -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash (ByteString -> Hash160)
-> (PublicKey -> ByteString) -> PublicKey -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ctx -> PublicKey -> ByteString
forall s a. Marshal s a => s -> a -> ByteString
marshal Ctx
ctx

-- | 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 :: Ctx -> PublicKey -> Address
pubKeyWitnessAddr :: Ctx -> PublicKey -> Address
pubKeyWitnessAddr Ctx
ctx =
  Hash160 -> Address
WitnessPubKeyAddress (Hash160 -> Address)
-> (PublicKey -> Hash160) -> PublicKey -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash (ByteString -> Hash160)
-> (PublicKey -> ByteString) -> PublicKey -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ctx -> PublicKey -> ByteString
forall s a. Marshal s a => s -> a -> ByteString
marshal Ctx
ctx

-- | Obtain a backwards-compatible SegWit P2SH-P2WPKH address from a public key.
pubKeyCompatWitnessAddr :: Ctx -> PublicKey -> Address
pubKeyCompatWitnessAddr :: Ctx -> PublicKey -> Address
pubKeyCompatWitnessAddr Ctx
ctx =
  Hash160 -> Address
p2shAddr
    (Hash160 -> Address)
-> (PublicKey -> Hash160) -> PublicKey -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash
    (ByteString -> Hash160)
-> (PublicKey -> ByteString) -> PublicKey -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ctx -> ScriptOutput -> ByteString
forall s a. Marshal s a => s -> a -> ByteString
marshal Ctx
ctx
    (ScriptOutput -> ByteString)
-> (PublicKey -> ScriptOutput) -> PublicKey -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash160 -> ScriptOutput
PayWitnessPKHash
    (Hash160 -> ScriptOutput)
-> (PublicKey -> Hash160) -> PublicKey -> ScriptOutput
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Hash160
forall b. ByteArrayAccess b => b -> Hash160
addressHash
    (ByteString -> Hash160)
-> (PublicKey -> ByteString) -> PublicKey -> Hash160
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ctx -> PublicKey -> ByteString
forall s a. Marshal s a => s -> a -> ByteString
marshal Ctx
ctx

-- | 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 :: Ctx -> ScriptOutput -> Address
payToScriptAddress :: Ctx -> ScriptOutput -> Address
payToScriptAddress Ctx
ctx = 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
. Ctx -> ScriptOutput -> ByteString
forall s a. Marshal s a => s -> a -> ByteString
marshal Ctx
ctx

-- | Compute a SegWit pay-to-witness-script-hash (P2WSH) address for an output
-- script.
payToWitnessScriptAddress :: Ctx -> ScriptOutput -> Address
payToWitnessScriptAddress :: Ctx -> ScriptOutput -> Address
payToWitnessScriptAddress Ctx
ctx = 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
. Ctx -> ScriptOutput -> ByteString
forall s a. Marshal s a => s -> a -> ByteString
marshal Ctx
ctx

-- | Compute a backwards-compatible SegWit P2SH-P2WSH address.
payToNestedScriptAddress :: Ctx -> ScriptOutput -> Address
payToNestedScriptAddress :: Ctx -> ScriptOutput -> Address
payToNestedScriptAddress Ctx
ctx =
  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
. Ctx -> ScriptOutput -> ByteString
forall s a. Marshal s a => s -> a -> ByteString
marshal Ctx
ctx (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
. Ctx -> ScriptOutput -> Script
encodeOutput Ctx
ctx

-- | 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 :: Ctx -> Address -> Script
addressToScript :: Ctx -> Address -> Script
addressToScript Ctx
ctx = Ctx -> ScriptOutput -> Script
encodeOutput Ctx
ctx (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 :: Ctx -> Address -> ByteString
addressToScriptBS :: Ctx -> Address -> ByteString
addressToScriptBS Ctx
ctx = 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 ()
forall (m :: * -> *). MonadPut m => Script -> m ()
serialize (Script -> Put) -> (Address -> Script) -> Putter Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ctx -> Address -> Script
addressToScript Ctx
ctx

-- | Decode an output script into an 'Address' if it has such representation.
scriptToAddress :: Ctx -> Script -> Either String Address
scriptToAddress :: Ctx -> Script -> Either String Address
scriptToAddress Ctx
ctx =
  String -> Maybe Address -> Either String Address
forall b a. b -> Maybe a -> Either b a
maybeToEither String
e (Maybe Address -> Either String Address)
-> (ScriptOutput -> Maybe Address)
-> ScriptOutput
-> Either String Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ctx -> ScriptOutput -> Maybe Address
outputAddress Ctx
ctx (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
<=< Ctx -> Script -> Either String ScriptOutput
decodeOutput Ctx
ctx
  where
    e :: String
e = String
"Could not decode address"

-- | Decode a serialized script into an 'Address'.
scriptToAddressBS :: Ctx -> ByteString -> Either String Address
scriptToAddressBS :: Ctx -> ByteString -> Either String Address
scriptToAddressBS Ctx
ctx =
  String -> Maybe Address -> Either String Address
forall b a. b -> Maybe a -> Either b a
maybeToEither String
e (Maybe Address -> Either String Address)
-> (ScriptOutput -> Maybe Address)
-> ScriptOutput
-> Either String Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ctx -> ScriptOutput -> Maybe Address
outputAddress Ctx
ctx (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
<=< Ctx -> ByteString -> Either String ScriptOutput
forall s a. Marshal s a => s -> ByteString -> Either String a
unmarshal Ctx
ctx
  where
    e :: String
e = String
"Could not decode address"

-- | Get the 'Address' of a 'ScriptOutput'.
outputAddress :: Ctx -> ScriptOutput -> Maybe Address
outputAddress :: Ctx -> ScriptOutput -> Maybe Address
outputAddress Ctx
ctx =
  \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 PublicKey
k -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ Ctx -> PublicKey -> Address
pubKeyAddr Ctx
ctx PublicKey
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 :: Ctx -> ScriptInput -> Maybe Address
inputAddress :: Ctx -> ScriptInput -> Maybe Address
inputAddress Ctx
ctx =
  \case
    (RegularInput (SpendPKHash TxSignature
_ PublicKey
key)) -> Address -> Maybe Address
forall a. a -> Maybe a
Just (Address -> Maybe Address) -> Address -> Maybe Address
forall a b. (a -> b) -> a -> b
$ Ctx -> PublicKey -> Address
pubKeyAddr Ctx
ctx PublicKey
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
$ Ctx -> ScriptOutput -> Address
payToScriptAddress Ctx
ctx ScriptOutput
rdm
    ScriptInput
_ -> Maybe Address
forall a. Maybe a
Nothing