packages feed

haskoin-core 0.8.4 → 0.9.0

raw patch · 14 files changed

+110/−78 lines, 14 files

Files

CHANGELOG.md view
@@ -4,9 +4,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.9.0+### Changed+- Address conversion to string now defined for all inputs.+ ## 0.8.4 ### Added - Add reward computation to block functions.+- Add PSBT [BIP-174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) types and functions  ## 0.8.3 ### Added
haskoin-core.cabal view
@@ -1,25 +1,26 @@--- This file has been generated from package.yaml by hpack version 0.28.2.+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.1. -- -- see: https://github.com/sol/hpack ----- hash: d2a9fa5a1034de67fddae041cd6e5f2473a5b97aa7951715ea23ef2c0154e909+-- hash: 88ebd4a51caa718564de69955c74a49d2279bc2d1fe883c83ae035f529168813  name:           haskoin-core-version:        0.8.4+version:        0.9.0 synopsis:       Bitcoin & Bitcoin Cash library for Haskell description:    Haskoin Core is a complete Bitcoin and Bitcoin Cash library of functions and data types for Haskell developers. category:       Bitcoin, Finance, Network homepage:       http://github.com/haskoin/haskoin#readme bug-reports:    http://github.com/haskoin/haskoin/issues author:         Philippe Laprade,-                Jean-Pierre Rupp+                Jean-Pierre Rupp,+                Matthew Wraith maintainer:     xenog@protonmail.com license:        PublicDomain license-file:   UNLICENSE build-type:     Simple-cabal-version:  >= 1.10 extra-source-files:-    CHANGELOG.md     data/forkid_script_tests.json     data/forkid_sighash.json     data/script_tests.json@@ -27,6 +28,7 @@     data/sig_strict.json     data/sighash.json     README.md+    CHANGELOG.md  source-repository head   type: git
src/Haskoin.hs view
@@ -21,6 +21,8 @@     , module Block       -- * Transactions     , module Transaction+      -- * Partially Signed Bitcoin Transactions+    , module Partial       -- * Scripts     , module Script       -- * Cryptographic Keys@@ -31,12 +33,13 @@     , module Util     ) where -import           Network.Haskoin.Address     as Address-import           Network.Haskoin.Block       as Block-import           Network.Haskoin.Constants   as Constants-import           Network.Haskoin.Crypto      as Crypto-import           Network.Haskoin.Keys        as Keys-import           Network.Haskoin.Network     as Network-import           Network.Haskoin.Script      as Script-import           Network.Haskoin.Transaction as Transaction-import           Network.Haskoin.Util        as Util+import           Network.Haskoin.Address             as Address+import           Network.Haskoin.Block               as Block+import           Network.Haskoin.Constants           as Constants+import           Network.Haskoin.Crypto              as Crypto+import           Network.Haskoin.Keys                as Keys+import           Network.Haskoin.Network             as Network+import           Network.Haskoin.Script              as Script+import           Network.Haskoin.Transaction         as Transaction+import           Network.Haskoin.Transaction.Partial as Partial+import           Network.Haskoin.Util                as Util
src/Network/Haskoin/Address.hs view
@@ -35,6 +35,7 @@     , addressToOutput     , payToScriptAddress     , payToWitnessScriptAddress+    , payToNestedScriptAddress     , scriptToAddress     , scriptToAddressBS       -- * Private Key Wallet Import Format (WIF)@@ -126,7 +127,7 @@ base58put _ _ = error "Cannot serialize this address as Base58"  addrToJSON :: Network -> Address -> Value-addrToJSON net = String . addrToString net+addrToJSON net a = toJSON (addrToString net a)  -- | JSON parsing for Bitcoin addresses. Works with 'Base58', 'CashAddr' and -- 'Bech32'.@@ -139,29 +140,23 @@  -- | Convert address to human-readable string. Uses 'Base58', 'Bech32', or -- 'CashAddr' depending on network.-addrToString :: Network -> Address -> Text+addrToString :: Network -> Address -> Maybe Text addrToString net a@PubKeyAddress {getAddrHash160 = h}     | isNothing (getCashAddrPrefix net) =-        encodeBase58Check $ runPut $ base58put net a+        Just . encodeBase58Check . runPut $ base58put net a     | otherwise =-        fromMaybe (error "Colud not encode a CashAddr") $         cashAddrEncode net 0 (S.encode h) addrToString net a@ScriptAddress {getAddrHash160 = h}     | isNothing (getCashAddrPrefix net) =-        encodeBase58Check $ runPut $ base58put net a+        Just . encodeBase58Check . runPut $ base58put net a     | otherwise =-        fromMaybe (error "Could not encode a CashAddr") $         cashAddrEncode net 1 (S.encode h)-addrToString net WitnessPubKeyAddress {getAddrHash160 = h} =-    let mt = do-            hrp <- getBech32Prefix net-            segwitEncode hrp 0 (B.unpack (S.encode h))-     in fromMaybe (error "Could not encode a Bech32 address") mt-addrToString net WitnessScriptAddress {getAddrHash256 = h} =-    let mt = do-            hrp <- getBech32Prefix net-            segwitEncode hrp 0 (B.unpack (S.encode h))-     in fromMaybe (error "Could not encode a Bech32 address") mt+addrToString net WitnessPubKeyAddress {getAddrHash160 = h} = do+    hrp <- getBech32Prefix net+    segwitEncode hrp 0 (B.unpack (S.encode h))+addrToString net WitnessScriptAddress {getAddrHash256 = h} = do+    hrp <- getBech32Prefix net+    segwitEncode hrp 0 (B.unpack (S.encode h))  -- | Parse 'Base58', 'Bech32' or 'CashAddr' address, depending on network. stringToAddr :: Network -> Text -> Maybe Address@@ -222,6 +217,11 @@ -- SegWit networks. payToWitnessScriptAddress :: ScriptOutput -> Address payToWitnessScriptAddress = p2wshAddr . sha256 . encodeOutputBS++-- | Compute a p2sh-p2wsh address, also known as a nested segwit address.+payToNestedScriptAddress :: ScriptOutput -> Address+payToNestedScriptAddress =+    p2shAddr . addressHash . encodeOutputBS . toP2WSH . encodeOutput  -- | Encode an output script from an address. Will fail if using a -- pay-to-witness address on a non-SegWit network.
src/Network/Haskoin/Block/Common.hs view
@@ -121,19 +121,19 @@ -- 'Block'. Variations in the coinbase will result in different merkle roots in -- the 'BlockHeader'. data BlockHeader =-    BlockHeader { blockVersion   :: !Word32      -- 16 bytes+    BlockHeader { blockVersion   :: !Word32      --  4 bytes                   -- | hash of the previous block (parent)-                , prevBlock      :: !BlockHash   -- 64 bytes+                , prevBlock      :: !BlockHash   -- 32 bytes                   -- | root of the merkle tree of transactions-                , merkleRoot     :: !Hash256     -- 64 bytes+                , merkleRoot     :: !Hash256     -- 32 bytes                   -- | unix timestamp-                , blockTimestamp :: !Timestamp   -- 16 bytes+                , blockTimestamp :: !Timestamp   --  4 bytes                   -- | difficulty target-                , blockBits      :: !Word32      -- 16 bytes+                , blockBits      :: !Word32      --  4 bytes                   -- | random nonce-                , bhNonce        :: !Word32      -- 16 bytes+                , bhNonce        :: !Word32      --  4 bytes                 } deriving (Eq, Ord, Show, Read, Generic, Hashable)-                                                 -- 208 bytes (above + 16 bytes)+                                                 -- 80 bytes  -- | Compute hash of 'BlockHeader'. headerHash :: BlockHeader -> BlockHash
src/Network/Haskoin/Keys/Extended.hs view
@@ -532,7 +532,7 @@     Deriv     -> Just Deriv     _         -> Nothing --- | Turn a derivatino path into a soft derivation path. Will fail if the path+-- | Turn a derivation path into a soft derivation path. Will fail if the path -- has hard derivations. toSoft :: DerivPathI t -> Maybe SoftPath toSoft p = case p of
src/Network/Haskoin/Transaction/Partial.hs view
@@ -3,7 +3,16 @@ {-# LANGUAGE NamedFieldPuns             #-} {-# LANGUAGE OverloadedStrings          #-} {-# LANGUAGE ScopedTypeVariables        #-}+{-|+Module      : Network.Haskoin.Transaction.Partial+Copyright   : No rights reserved+License     : UNLICENSE+Maintainer  : matt@bitnomial.com+Stability   : experimental+Portability : POSIX +Code related to PSBT parsing and serialization.+-} module Network.Haskoin.Transaction.Partial     ( PartiallySignedTransaction (..)     , Input (..)@@ -29,26 +38,27 @@ import qualified Data.HashMap.Strict         as HashMap import           Data.List                   (foldl') import           Data.Maybe                  (fromMaybe, isJust)-import           Data.Proxy                  (Proxy) import           Data.Serialize              as S import           GHC.Generics                (Generic)-import           GHC.Word                    (Word64, Word8)+import           GHC.Word                    (Word32, Word8) import           Network.Haskoin.Address     (Address (..), pubKeyAddr) import           Network.Haskoin.Keys        (Fingerprint, KeyIndex, PubKeyI) import           Network.Haskoin.Network     (VarInt (..), VarString (..),                                               putVarInt)-import           Network.Haskoin.Script      (Script (..), ScriptInput (..),-                                              ScriptOp (..), ScriptOutput (..),-                                              SigHash, SimpleInput (..),+import           Network.Haskoin.Script      (Script (..), ScriptOp (..),+                                              ScriptOutput (..), SigHash,                                               decodeOutput, decodeOutputBS,-                                              encodeInput, encodeOutputBS,-                                              isPayScriptHash, opPushData,-                                              toP2SH, toP2WSH)+                                              encodeOutputBS, isPayScriptHash,+                                              opPushData, toP2SH, toP2WSH) import           Network.Haskoin.Transaction (Tx (..), TxOut, WitnessStack,                                               outPointIndex, prevOutput,                                               scriptInput, scriptOutput) import           Network.Haskoin.Util        (eitherToMaybe) +-- | PSBT data type as specified in [BIP-174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki). This+-- contains an unsigned transaction, inputs and outputs, and unspecified extra data. There is one input per input in the+-- unsigned transaction, and one output per output in the unsigned transaction. The inputs and outputs in the+-- 'PartiallySignedTransaction' line up by index with the inputs and outputs in the unsigned transaction. data PartiallySignedTransaction = PartiallySignedTransaction     { unsignedTransaction :: Tx     , globalUnknown       :: UnknownMap@@ -56,6 +66,7 @@     , outputs             :: [Output]     } deriving (Show, Eq) +-- | Inputs contain all of the data needed to sign a transaction and all of the resulting signature data after signing. data Input = Input     { nonWitnessUtxo     :: Maybe Tx     , witnessUtxo        :: Maybe TxOut@@ -69,6 +80,7 @@     , inputUnknown       :: UnknownMap     } deriving (Show, Eq) +-- | Outputs can contain information needed to spend the output at a later date. data Output = Output     { outputRedeemScript  :: Maybe Script     , outputWitnessScript :: Maybe Script@@ -76,9 +88,12 @@     , outputUnknown       :: UnknownMap     } deriving (Show, Eq) +-- | A map of raw PSBT keys to byte strings for extra data. The 'keyType' field cannot overlap with any of the reserved+-- 'keyType' fields specified in the PSBT specification. newtype UnknownMap = UnknownMap { unknownMap :: HashMap Key ByteString }     deriving (Show, Eq, Semigroup, Monoid) +-- | Raw keys for the map type used in PSBTs. data Key = Key     { keyType :: Word8     , key     :: ByteString@@ -86,6 +101,7 @@  instance Hashable Key +-- | Take two 'PartiallySignedTransaction's and merge them. The 'unsignedTransaction' field in both must be the same. merge :: PartiallySignedTransaction -> PartiallySignedTransaction -> Maybe PartiallySignedTransaction merge psbt1 psbt2     | unsignedTransaction psbt1 == unsignedTransaction psbt2@@ -120,8 +136,9 @@     , outputUnknown = outputUnknown a <> outputUnknown b     } +-- | Take partial signatures from all of the 'Input's and finalize the signature. complete :: PartiallySignedTransaction -> PartiallySignedTransaction-complete psbt = psbt { inputs = map (completeInput . analyzeInputs) (zip [0..] $ inputs psbt) }+complete psbt = psbt { inputs = map (completeInput . analyzeInputs) (indexed $ inputs psbt) }   where     analyzeInputs (i, input) = (outputScript =<< witnessUtxo input <|> nonWitScript, input)       where@@ -129,13 +146,16 @@      getPrevOut i tx =        (txOut tx !!?) . fromIntegral . outPointIndex . prevOutput =<< txIn (unsignedTransaction psbt) !!? i-    xs !!? i = lookup i $ zip [0..] xs+    xs !!? i = lookup i $ indexed xs      outputScript = eitherToMaybe . decodeOutputBS . scriptOutput      completeInput (Nothing, input)     = input     completeInput (Just script, input) = completeSig input script +    indexed :: [a] -> [(Word32, a)]+    indexed = zip [0..]+ completeSig :: Input -> ScriptOutput -> Input completeSig input (PayPK k) =     input { finalScriptSig = eitherToMaybe . S.decode =<< HashMap.lookup k (partialSigs input) }@@ -182,6 +202,8 @@   where     lookupKey sigs key = maybe sigs (:sigs) $ HashMap.lookup key (partialSigs input) +-- | Take a finalized 'PartiallySignedTransaction' and produce the signed final transaction.  You may need to call+-- 'complete' on the 'PartiallySignedTransaction' before producing the final transaction. finalTransaction :: PartiallySignedTransaction -> Tx finalTransaction psbt = setInputs . foldl' finalizeInput ([], []) $ zip (txIn tx) (inputs psbt)   where@@ -193,6 +215,7 @@         finalScript script = (txInput { scriptInput = encode script }:ins, []:witData)         finalWitness = (ins, fromMaybe [] (finalScriptWitness psbtInput):witData) +-- | Take an unsigned transaction and produce an empty 'PartiallySignedTransaction' emptyPSBT :: Tx -> PartiallySignedTransaction emptyPSBT tx = PartiallySignedTransaction     { unsignedTransaction = tx@@ -298,7 +321,7 @@       where         putPartialSig = putPubKeyMap InPartialSig . fmap VarString         putSigHash sigHash = do-            putVarInt 1 >> putWord8 (enumWord8 InSigHashType)+            putKey InSigHashType             putWord8 0x04             putWord32le (fromIntegral sigHash) @@ -322,8 +345,11 @@ getSizedBytes = getNested (fromIntegral . getVarInt <$> get) get  putKeyValue :: (Enum t, Serialize v) => t -> v -> Put-putKeyValue t v = putVarInt 1 >> putWord8 (enumWord8 t) >> putSizedBytes v+putKeyValue t v = putKey t >> putSizedBytes v +putKey :: Enum t => t -> Put+putKey t = putVarInt (1 :: Word8) >> putWord8 (enumWord8 t)+ getMap :: (Bounded t, Enum t)        => (Int -> a -> t -> Get a)        -> ((HashMap Key ByteString -> HashMap Key ByteString) -> a -> a)@@ -367,10 +393,10 @@     utxo <- getSizedBytes     return $ input { witnessUtxo = Just utxo } getInputItem keySize input InPartialSig = do-    (k, v) <- getPartialSig keySize+    (k, v) <- getPartialSig     return $ input { partialSigs = HashMap.insert k v (partialSigs input) }   where-    getPartialSig keySize = (,) <$> isolate keySize get <*> (getVarString <$> get)+    getPartialSig = (,) <$> isolate keySize get <*> (getVarString <$> get) getInputItem 0 input@Input{sigHashType = Nothing} InSigHashType = do     VarInt size <- get     guard $ size == 0x04
src/Network/Haskoin/Util.hs view
@@ -41,7 +41,7 @@     ) where  import           Control.Monad          (guard)-import           Control.Monad.Except   (ExceptT (..))+import           Control.Monad.Except   (ExceptT (..), liftEither) import           Data.Aeson.Types       (Options (..), SumEncoding (..),                                          defaultOptions, defaultTaggedObject) import           Data.Bits@@ -107,10 +107,6 @@ -- 'Right' and 'Nothing' is mapped to 'Left'. Default 'Left' required. maybeToEither :: b -> Maybe a -> Either b a maybeToEither err = maybe (Left err) Right---- | Lift a 'Either' computation into the 'ExceptT' monad.-liftEither :: Monad m => Either b a -> ExceptT b m a-liftEither = ExceptT . return  -- | Lift a 'Maybe' computation into the 'ExceptT' monad. liftMaybe :: Monad m => b -> Maybe a -> ExceptT b m a
test/Network/Haskoin/Address/CashAddrSpec.hs view
@@ -44,79 +44,79 @@     describe "cashaddr to base58 translation test vectors" $ do         it "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu" $ do             let addr =-                    addrToString bch <$>+                    addrToString bch =<<                     stringToAddr btc "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu"             addr `shouldBe`                 Just "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"         it "1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR" $ do             let addr =-                    addrToString bch <$>+                    addrToString bch =<<                     stringToAddr btc "1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR"             addr `shouldBe`                 Just "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy"         it "16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb" $ do             let addr =-                    addrToString bch <$>+                    addrToString bch =<<                     stringToAddr btc "16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb"             addr `shouldBe`                 Just "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"         it "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC" $ do             let addr =-                    addrToString bch <$>+                    addrToString bch =<<                     stringToAddr btc "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC"             addr `shouldBe`                 Just "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"         it "3LDsS579y7sruadqu11beEJoTjdFiFCdX4" $ do             let addr =-                    addrToString bch <$>+                    addrToString bch =<<                     stringToAddr btc "3LDsS579y7sruadqu11beEJoTjdFiFCdX4"             addr `shouldBe`                 Just "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e"         it "31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw" $ do             let addr =-                    addrToString bch <$>+                    addrToString bch =<<                     stringToAddr btc "31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw"             addr `shouldBe`                 Just "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"     describe "base58 to cashaddr translation test vectors" $ do         it "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a" $ do             let addr =-                    addrToString btc <$>+                    addrToString btc =<<                     stringToAddr                         bch                         "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"             addr `shouldBe` Just "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu"         it "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy" $ do             let addr =-                    addrToString btc <$>+                    addrToString btc =<<                     stringToAddr                         bch                         "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy"             addr `shouldBe` Just "1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR"         it "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r" $ do             let addr =-                    addrToString btc <$>+                    addrToString btc =<<                     stringToAddr                         bch                         "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"             addr `shouldBe` Just "16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb"         it "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq" $ do             let addr =-                    addrToString btc <$>+                    addrToString btc =<<                     stringToAddr                         bch                         "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"             addr `shouldBe` Just "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC"         it "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e" $ do             let addr =-                    addrToString btc <$>+                    addrToString btc =<<                     stringToAddr                         bch                         "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e"             addr `shouldBe` Just "3LDsS579y7sruadqu11beEJoTjdFiFCdX4"         it "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37" $ do             let addr =-                    addrToString btc <$>+                    addrToString btc =<<                     stringToAddr                         bch                         "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"
test/Network/Haskoin/AddressSpec.hs view
@@ -39,7 +39,7 @@     it "encodes and decodes address" $         property $         forAll arbitraryAddress $ \a ->-            stringToAddr net (addrToString net a) == Just a+            (stringToAddr net =<< addrToString net a) == Just a     it "shows and reads address" $         property $ forAll arbitraryAddress $ \a -> read (show a) == a 
test/Network/Haskoin/CryptoSpec.hs view
@@ -136,10 +136,10 @@  checkMatchingAddress :: Assertion checkMatchingAddress = do-    assertBool "Key 1"  $ addr1  == addrToString btc (pubKeyAddr pub1)-    assertBool "Key 2"  $ addr2  == addrToString btc (pubKeyAddr pub2)-    assertBool "Key 1C" $ addr1C == addrToString btc (pubKeyAddr pub1C)-    assertBool "Key 2C" $ addr2C == addrToString btc (pubKeyAddr pub2C)+    assertBool "Key 1"  $ Just addr1  == addrToString btc (pubKeyAddr pub1)+    assertBool "Key 2"  $ Just addr2  == addrToString btc (pubKeyAddr pub2)+    assertBool "Key 1C" $ Just addr1C == addrToString btc (pubKeyAddr pub1C)+    assertBool "Key 2C" $ Just addr2C == addrToString btc (pubKeyAddr pub2C)  checkSignatures :: Hash256 -> Assertion checkSignatures h = do
test/Network/Haskoin/Keys/ExtendedSpec.hs view
@@ -293,7 +293,7 @@     assertBool "xPrvID" $ encodeHex (S.encode $ xPrvID m) == head v     assertBool "xPrvFP" $ encodeHex (S.encode $ xPrvFP m) == v !! 1     assertBool "xPrvAddr" $-        addrToString btc (xPubAddr $ deriveXPubKey m) == v !! 2+        addrToString btc (xPubAddr $ deriveXPubKey m) == Just (v !! 2)     assertBool "prvKey" $ encodeHex (getSecKey $ xPrvKey m) == v !! 3     assertBool "xPrvWIF" $ xPrvWif btc m == v !! 4     assertBool "pubKey" $
test/Network/Haskoin/ScriptSpec.hs view
@@ -364,7 +364,7 @@     b = do         o <- s         d <- eitherToMaybe $ decodeOutput o-        return . addrToString btc $ payToScriptAddress d+        addrToString btc $ payToScriptAddress d  sigDecodeMap :: Network -> (Text, Int) -> Spec sigDecodeMap net (_, i) =
test/Network/Haskoin/TransactionSpec.hs view
@@ -170,7 +170,7 @@     | isScriptAddress a = Right (PayScriptHash (getAddrHash160 a)) == out     | otherwise = undefined   where-    tx = buildAddrTx net [] [(addrToString net a, v)]+    tx = buildAddrTx net [] [(fromJust (addrToString net a), v)]     out =         decodeOutputBS $         scriptOutput $