{-# LANGUAGE StrictData #-}
module Bitcoin.Address
(
btc
, btcTestnet
, Address(..)
, renderAddress
, addressScript
, p2pkh
, p2sh
, p2sh_multiSig
, p2sh_p2wpkh
, p2sh_p2wsh
, p2sh_p2wsh_multiSig
, p2wpkh
, p2wsh
, p2wsh_multiSig
) where
import Bitcoin.Keys (Pub)
import Bitcoin.Hash (check32)
import qualified Data.Bitcoin.Script as S
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Base58 as B58
import Bitcoin.Address.Hash
import qualified Bitcoin.Address.Script as XS
import qualified Bitcoin.Address.SegWit as SW
import Bitcoin.Address.Settings
data Address
= P2PKH PrefixP2PKH PubHash160
| P2SH PrefixP2SH ScriptHash160
| SegWit PrefixSegWit SW.Program
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)
instance Show Address where
show :: Address -> String
show = ByteString -> String
B8.unpack (ByteString -> String)
-> (Address -> ByteString) -> Address -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Address -> ByteString
renderAddress
p2pkh :: Settings -> Pub -> Address
p2pkh :: Settings -> Pub -> Address
p2pkh sett :: Settings
sett = PrefixP2PKH -> PubHash160 -> Address
P2PKH (Settings -> PrefixP2PKH
settings_prefixP2PKH Settings
sett) (PubHash160 -> Address) -> (Pub -> PubHash160) -> Pub -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pub -> PubHash160
pubHash160
p2sh :: Settings -> S.Script -> Address
p2sh :: Settings -> Script -> Address
p2sh sett :: Settings
sett = PrefixP2SH -> ScriptHash160 -> Address
P2SH (Settings -> PrefixP2SH
settings_prefixP2SH Settings
sett) (ScriptHash160 -> Address)
-> (Script -> ScriptHash160) -> Script -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Script -> ScriptHash160
scriptHash160
p2sh_p2wpkh :: Settings -> Pub -> Address
p2sh_p2wpkh :: Settings -> Pub -> Address
p2sh_p2wpkh sett :: Settings
sett = Settings -> Script -> Address
p2sh Settings
sett (Script -> Address) -> (Pub -> Script) -> Pub -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Program -> Script
XS.segWit (Program -> Script) -> (Pub -> Program) -> Pub -> Script
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PubHash160 -> Program
SW.p2wpkh (PubHash160 -> Program) -> (Pub -> PubHash160) -> Pub -> Program
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pub -> PubHash160
pubHash160
p2sh_multiSig
:: Settings
-> [Pub]
-> Int
-> Maybe Address
p2sh_multiSig :: Settings -> [Pub] -> Int -> Maybe Address
p2sh_multiSig sett :: Settings
sett pks :: [Pub]
pks req :: Int
req = Settings -> Script -> Address
p2sh Settings
sett (Script -> Address) -> Maybe Script -> Maybe Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Pub] -> Int -> Maybe Script
XS.multiSig [Pub]
pks Int
req
p2sh_p2wsh :: Settings -> S.Script -> Address
p2sh_p2wsh :: Settings -> Script -> Address
p2sh_p2wsh sett :: Settings
sett = Settings -> Script -> Address
p2sh Settings
sett (Script -> Address) -> (Script -> Script) -> Script -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Program -> Script
XS.segWit (Program -> Script) -> (Script -> Program) -> Script -> Script
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptSHA256 -> Program
SW.p2wsh (ScriptSHA256 -> Program)
-> (Script -> ScriptSHA256) -> Script -> Program
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Script -> ScriptSHA256
scriptSHA256
p2sh_p2wsh_multiSig
:: Settings
-> [Pub]
-> Int
-> Maybe Address
p2sh_p2wsh_multiSig :: Settings -> [Pub] -> Int -> Maybe Address
p2sh_p2wsh_multiSig sett :: Settings
sett pks :: [Pub]
pks req :: Int
req = Settings -> Script -> Address
p2sh_p2wsh Settings
sett (Script -> Address) -> Maybe Script -> Maybe Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Pub] -> Int -> Maybe Script
XS.multiSig [Pub]
pks Int
req
p2wpkh :: Settings -> Pub -> Address
p2wpkh :: Settings -> Pub -> Address
p2wpkh sett :: Settings
sett = PrefixSegWit -> Program -> Address
SegWit (Settings -> PrefixSegWit
settings_prefixSegWit Settings
sett) (Program -> Address) -> (Pub -> Program) -> Pub -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PubHash160 -> Program
SW.p2wpkh (PubHash160 -> Program) -> (Pub -> PubHash160) -> Pub -> Program
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pub -> PubHash160
pubHash160
p2wsh :: Settings -> S.Script -> Address
p2wsh :: Settings -> Script -> Address
p2wsh sett :: Settings
sett = PrefixSegWit -> Program -> Address
SegWit (Settings -> PrefixSegWit
settings_prefixSegWit Settings
sett) (Program -> Address) -> (Script -> Program) -> Script -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScriptSHA256 -> Program
SW.p2wsh (ScriptSHA256 -> Program)
-> (Script -> ScriptSHA256) -> Script -> Program
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Script -> ScriptSHA256
scriptSHA256
p2wsh_multiSig
:: Settings
-> [Pub]
-> Int
-> Maybe Address
p2wsh_multiSig :: Settings -> [Pub] -> Int -> Maybe Address
p2wsh_multiSig sett :: Settings
sett pks :: [Pub]
pks req :: Int
req = Settings -> Script -> Address
p2wsh Settings
sett (Script -> Address) -> Maybe Script -> Maybe Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Pub] -> Int -> Maybe Script
XS.multiSig [Pub]
pks Int
req
addressScript :: Address -> S.Script
addressScript :: Address -> Script
addressScript = \case
P2PKH _ pkh :: PubHash160
pkh -> PubHash160 -> Script
XS.p2pkh PubHash160
pkh
P2SH _ sh :: ScriptHash160
sh -> ScriptHash160 -> Script
XS.p2sh ScriptHash160
sh
SegWit _ swp :: Program
swp -> Program -> Script
XS.segWit Program
swp
renderAddress :: Address -> B.ByteString
renderAddress :: Address -> ByteString
renderAddress = \case
P2PKH pre :: PrefixP2PKH
pre pkh :: PubHash160
pkh -> ByteString -> ByteString
toBase58Check (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Word8 -> ByteString -> ByteString
B.cons (PrefixP2PKH -> Word8
unPrefixP2PKH PrefixP2PKH
pre) (PubHash160 -> ByteString
unPubHash160 PubHash160
pkh)
P2SH pre :: PrefixP2SH
pre sh :: ScriptHash160
sh -> ByteString -> ByteString
toBase58Check (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Word8 -> ByteString -> ByteString
B.cons (PrefixP2SH -> Word8
unPrefixP2SH PrefixP2SH
pre) (ScriptHash160 -> ByteString
unScriptHash160 ScriptHash160
sh)
SegWit pre :: PrefixSegWit
pre swp :: Program
swp -> PrefixSegWit -> Program -> ByteString
SW.renderProgram PrefixSegWit
pre Program
swp
toBase58Check :: B.ByteString -> B.ByteString
{-# INLINE toBase58Check #-}
toBase58Check :: ByteString -> ByteString
toBase58Check a :: ByteString
a = Alphabet -> ByteString -> ByteString
B58.encodeBase58 Alphabet
B58.bitcoinAlphabet (ByteString
a ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString -> ByteString
check32 ByteString
a)
btc :: Settings
btc :: Settings
btc = PrefixP2PKH -> PrefixP2SH -> PrefixSegWit -> Settings
Settings PrefixP2PKH
btc_prefixP2PKH PrefixP2SH
btc_prefixP2SH PrefixSegWit
btc_prefixSegWit
btc_prefixP2PKH :: PrefixP2PKH
btc_prefixP2PKH :: PrefixP2PKH
btc_prefixP2PKH = Word8 -> PrefixP2PKH
PrefixP2PKH 0x00
btc_prefixP2SH :: PrefixP2SH
btc_prefixP2SH :: PrefixP2SH
btc_prefixP2SH = Word8 -> PrefixP2SH
PrefixP2SH 0x05
btc_prefixSegWit :: PrefixSegWit
Just btc_prefixSegWit :: PrefixSegWit
btc_prefixSegWit = ByteString -> Maybe PrefixSegWit
prefixSegWit "bc"
btcTestnet :: Settings
btcTestnet :: Settings
btcTestnet = PrefixP2PKH -> PrefixP2SH -> PrefixSegWit -> Settings
Settings PrefixP2PKH
btcTestnet_prefixP2PKH PrefixP2SH
btcTestnet_prefixP2SH
PrefixSegWit
btcTestnet_prefixSegWit
btcTestnet_prefixP2PKH :: PrefixP2PKH
btcTestnet_prefixP2PKH :: PrefixP2PKH
btcTestnet_prefixP2PKH = Word8 -> PrefixP2PKH
PrefixP2PKH 0x6f
btcTestnet_prefixP2SH :: PrefixP2SH
btcTestnet_prefixP2SH :: PrefixP2SH
btcTestnet_prefixP2SH = Word8 -> PrefixP2SH
PrefixP2SH 0xc4
btcTestnet_prefixSegWit :: PrefixSegWit
Just btcTestnet_prefixSegWit :: PrefixSegWit
btcTestnet_prefixSegWit = ByteString -> Maybe PrefixSegWit
prefixSegWit "tb"