{-# LANGUAGE ScopedTypeVariables #-} module Network.EasyBitcoin.Address where import Network.EasyBitcoin.Internal.Words import Network.EasyBitcoin.Internal.Base58 ( encodeBase58 , decodeBase58 , addRedundancy , liftRedundacy ) import Network.EasyBitcoin.Internal.ByteString import Network.EasyBitcoin.Internal.InstanciationHelpers import Network.EasyBitcoin.Internal.HashFunctions import Network.EasyBitcoin.Internal.Keys (PrvKey(), PubKey(),Compressed(..)) import Network.EasyBitcoin.Keys import Network.EasyBitcoin.NetworkParams import qualified Data.ByteString as BS import Data.Char(isSpace) import Data.Word -- | Bitcoin address, either Pay2PKH or Pay2SH data Address net = PubKeyAddress { getAddrHash :: Word160 } | ScriptAddress { getAddrHash :: Word160 } deriving (Eq, Ord) -- | Values from where an address can be derived. Keys, are interpreted as compressed by default, if need to derive an address from -- an uncompressed key, use 'addressFromUncompressed' instead. class Addressable add where address :: (BlockNetwork net) => add net -> Address net -- | As addresses are obtained from public keys hashes, when deriving from a private key, it will first get derived to public -- -- prop> address key = address (derivePublic key) -- -- Addresses derived from Keys will always be Pay2PKH addresses: -- -- prop> isPay2PKH (address key) = True instance Addressable (Key v) where address = PubKeyAddress . hash160 . hash256BS . encode' . Compressed True. pub_key . derivePublic -- | Derive an address from a key as uncompressed. addressFromUncompressed:: Key v net -> Address net addressFromUncompressed = PubKeyAddress . hash160 . hash256BS . encode' . Compressed False . pub_key . derivePublic -- | Address was derived from an script hash. Though these addresses can represent the hash of any script, only redeem -- scripts for multi-signature are currently supported. isPay2SH :: Address net -> Bool isPay2SH addr = case addr of PubKeyAddress _ -> True _ -> False -- | Address was derived from a public key hash. isPay2PKH :: Address net -> Bool isPay2PKH addr = case addr of ScriptAddress _ -> True _ -> False --------------------------------------------------------------------------------------------------------------------------------- instance (BlockNetwork net ) => Show (Address net) where show = show_aux where show_aux :: forall net . (BlockNetwork net ) => Address net -> String show_aux addr = let params = (valuesOf :: Params net) in case addr of PubKeyAddress payload -> show_ (addrPrefix params) payload ScriptAddress payload -> show_ (scriptPrefix params) payload instance (BlockNetwork net ) => Read (Address net) where readsPrec _ = read_aux where read_aux :: forall net . (BlockNetwork net ) => ReadS (Address net) read_aux str = let params = (valuesOf :: Params net) in case readsPrec_ str of ( Just (prefix, payload), rest) | addrPrefix params == prefix -> [(PubKeyAddress payload, rest)] | scriptPrefix params == prefix -> [(ScriptAddress payload, rest)] _ -> [] ----------------------------------------------------------------------------------------------------------------------------------