packages feed

haskoin-wallet-0.0.1: tests/Network/Haskoin/Wallet/Store/Units.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GADTs             #-}
{-# LANGUAGE TypeFamilies      #-}
module Network.Haskoin.Wallet.Store.Units (tests) where

import Test.HUnit (Assertion, assertBool, assertEqual)
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.HUnit (testCase)

import Control.Applicative ((<$>))
import Control.Monad.Trans (liftIO, lift)
import Control.Monad.Trans.Either (EitherT, runEitherT)

import Data.Maybe (fromJust, isJust)
import Data.Yaml as YAML
    ( Value
    , object 
    , toJSON
    , (.=)
    )
import qualified Data.Text as T (pack)

import Database.Persist 
    ( PersistStore
    , PersistUnique
    , PersistQuery
    , PersistMonadBackend
    , Entity(..)
    , entityVal
    , getBy
    , selectList
    , count
    , (==.)
    , Filter
    , SelectOpt(Asc)
    )
import Database.Persist.Sqlite (SqlBackend, runSqlite, runMigration)

import Network.Haskoin.Wallet
import Network.Haskoin.Wallet.Store
import Network.Haskoin.Wallet.Store.DbAddress
import Network.Haskoin.Wallet.Store.DbAccount
import Network.Haskoin.Wallet.Store.Util
import Network.Haskoin.Script
import Network.Haskoin.Util

tests :: [Test]
tests =
    [ testGroup "Wallet persistence tests" 
        [ testCase "Wallet tests" runTests
        ] 
    ]

runTests :: Assertion
runTests = do
    _ <- runSqlite ":memory:" $ runEitherT $ do
        lift $ runMigration migrateAll
        liftIO . (assertBool "Pre init") . isRight =<< runEitherT testPreInit
        liftIO . (assertBool "Init") . isRight =<< runEitherT testInit
        liftIO . (assertBool "New Acc") . isRight =<< runEitherT testNewAcc
        liftIO . (assertBool "New MS") . isRight =<< runEitherT testNewMS
        liftIO . (assertBool "Gen Addr") . isRight =<< runEitherT testGenAddr
        liftIO . (assertBool "Import Tx") . isRight =<< runEitherT testImport
        liftIO . (assertBool "Orphan Tx") . isRight =<< runEitherT testOrphan
        liftIO . (assertBool "Send Tx") . isRight =<< runEitherT testSend
        liftIO . (assertBool "Utilities") . isRight =<< runEitherT testUtil
    return ()

testPreInit :: (PersistStore m, PersistUnique m, PersistQuery m) 
            => EitherT String m ()
testPreInit = do 
    -- Creating a new account without initializing the wallet should fail
    runEitherT (cmdNewAcc "default") >>= 
        liftIO . assertEqual "Invalid wallet" 
            (Left "dbGetWallet: Invalid wallet main")

    -- Listing addresses without initializing the wallet should fail
    runEitherT (cmdList "default" 0 1) >>= 
        liftIO . assertEqual "Invalid account" 
            (Left "dbGetAcc: Invalid account default")

    -- Displaying page numbe -1 should fail
    runEitherT (cmdList "default" (-1) 1) >>= 
        liftIO . assertEqual "Invalid page number" 
            (Left "cmdList: Invalid page number -1")

    -- Displaying 0 results per page should fail
    runEitherT (cmdList "default" 0 0) >>= 
        liftIO . assertEqual "Invalid results per page" 
            (Left "cmdList: Invalid results per page 0")

testInit :: (PersistStore m, PersistUnique m, PersistQuery m) 
         => EitherT String m ()
testInit = do 

    -- Initializing the wallet with an empty seed should fail
    runEitherT (cmdInit "") >>= liftIO . assertEqual "Init empty seed" 
        (Left "cmdInit: seed can not be empty") 

    -- Initialize wallet with seed "Hello World"
    _ <- cmdInit "Hello World" 

    walletE <- getBy $ UniqueWalletName "main"
    
    -- Get the "main" wallet from the database
    liftIO $ assertBool "Wallet init" $ isJust walletE

    let (Entity _ w) = fromJust walletE
        key          = fromJust $ makeMasterKey $ stringToBS "Hello World"
        keystr       = xPrvExport $ masterKey key

    -- Check wallet master key
    liftIO $ assertEqual "Wallet master key" keystr $ dbWalletMaster w

    -- Check wallet name
    liftIO $ assertEqual "Wallet name" "main" $ dbWalletName w

    -- Generate addresses on an invalid account should fail
    runEitherT (cmdGenAddrs "default" 5) >>= liftIO . 
        assertEqual "Invalid account" 
        (Left "dbGetAcc: Invalid account default") 

    -- Address count in the database should be 0 at this point
    count ([] :: [Filter (DbAddressGeneric b)]) >>= 
        liftIO . assertEqual "Address count" 0

testNewAcc :: (PersistStore m, PersistUnique m, PersistQuery m) 
           => EitherT String m ()
testNewAcc = do 

    -- Create a new account with empty name ""
    cmdNewAcc "" >>= liftIO . assertEqual "New acc 1"
       ( object 
           [ "Name" .= T.pack ""
           , "Tree" .= T.pack "m/0'/"
           , "Type" .= T.pack "Regular"
           ] 
       )

    -- Check the wallet account index
    (dbWalletAccIndex . entityVal <$> dbGetWallet "main") >>= 
        liftIO . assertEqual "acc index 0" 0

    -- Create a new account named "acc1"
    cmdNewAcc "acc1" >>= liftIO . assertEqual "New acc 2"
        ( object 
            [ "Name" .= T.pack "acc1"
            , "Tree" .= T.pack "m/1'/"
            , "Type" .= T.pack "Regular"
            ] 
        )

    -- Check the wallet account index
    (dbWalletAccIndex . entityVal <$> dbGetWallet "main") >>= 
        liftIO . assertEqual "acc index 1" 1

    -- Create a new account named "acc2"
    cmdNewAcc "acc2" >>= liftIO . assertEqual "New acc 3"
        ( object 
            [ "Name" .= T.pack "acc2"
            , "Tree" .= T.pack "m/2'/"
            , "Type" .= T.pack "Regular"
            ] 
        )

    -- Check the wallet account index
    (dbWalletAccIndex . entityVal <$> dbGetWallet "main") >>= 
        liftIO . assertEqual "acc index 2" 2

    -- List all accounts created up to now
    cmdListAcc >>= liftIO . assertEqual "List accs"
        ( toJSON
            [ object 
                [ "Name" .= T.pack ""
                , "Tree" .= T.pack "m/0'/"
                , "Type" .= T.pack "Regular"
                ] 
            , object 
                [ "Name" .= T.pack "acc1"
                , "Tree" .= T.pack "m/1'/"
                , "Type" .= T.pack "Regular"
                ] 
            , object 
                [ "Name" .= T.pack "acc2"
                , "Tree" .= T.pack "m/2'/"
                , "Type" .= T.pack "Regular"
                ] 
            ]
        )

    -- Initialize some keys for future tests
    let mstKey = fromJust $ makeMasterKey $ stringToBS "Hello World"
        prvKey = getAccPrvKey $ fromJust $ accPrvKey mstKey 1
        pubKey = deriveXPubKey prvKey
       
    -- Dump keys for account "acc1"
    cmdDumpKeys "acc1" >>= liftIO . assertEqual "Dump keys"
        ( object 
            [ "Account" .= object 
                [ "Name" .= T.pack "acc1"
                , "Tree" .= T.pack "m/1'/"
                , "Type" .= T.pack "Regular"
                ] 
            , "PubKey"  .= xPubExport pubKey
            , "PrvKey"  .= xPrvExport prvKey
            ]
        )

    -- Display account information for account "acc2"
    cmdAccInfo "acc2" >>= liftIO . assertEqual "Acc info" 
        ( object 
            [ "Name" .= T.pack "acc2"
            , "Tree" .= T.pack "m/2'/"
            , "Type" .= T.pack "Regular"
            ] 
        )

    -- Count accounts in the database created up to now
    count ([] :: [Filter (DbAccountGeneric b)]) >>= 
        liftIO . assertEqual "Acc count" 3

    -- Check that address-related data and gaps are correct
    (Entity a1 acc1) <- dbGetAcc ""
    (Entity a2 acc2) <- dbGetAcc "acc1"
    (Entity a3 acc3) <- dbGetAcc "acc2"

    count [DbAddressAccount ==. a1, DbAddressInternal ==. True] >>=
        liftIO . assertEqual "Int gap address count" 30

    count [DbAddressAccount ==. a1, DbAddressInternal ==. False] >>=
        liftIO . assertEqual "Ext gap address count" 30

    count [DbAddressAccount ==. a2, DbAddressInternal ==. True] >>=
        liftIO . assertEqual "Int gap address count 2" 30

    count [DbAddressAccount ==. a2, DbAddressInternal ==. False] >>=
        liftIO . assertEqual "Ext gap address count 2" 30

    count [DbAddressAccount ==. a3, DbAddressInternal ==. True] >>=
        liftIO . assertEqual "Int gap address count 3" 30

    count [DbAddressAccount ==. a3, DbAddressInternal ==. False] >>=
        liftIO . assertEqual "Ext gap address count 3" 30

    liftIO $ assertEqual "ExtIndex acc 1" (-1) (dbAccountExtIndex acc1)
    liftIO $ assertEqual "IntIndex acc 1" (-1) (dbAccountIntIndex acc1)
    liftIO $ assertEqual "ExtGap acc 1"    29  (dbAccountExtGap acc1)
    liftIO $ assertEqual "IntGap acc 1"    29  (dbAccountIntGap acc1)

    liftIO $ assertEqual "ExtIndex acc 2" (-1) (dbAccountExtIndex acc2)
    liftIO $ assertEqual "IntIndex acc 2" (-1) (dbAccountIntIndex acc2)
    liftIO $ assertEqual "ExtGap acc 2"    29  (dbAccountExtGap acc2)
    liftIO $ assertEqual "IntGap acc 2"    29  (dbAccountIntGap acc2)

    liftIO $ assertEqual "ExtIndex acc 3" (-1) (dbAccountExtIndex acc3)
    liftIO $ assertEqual "IntIndex acc 3" (-1) (dbAccountIntIndex acc3)
    liftIO $ assertEqual "ExtGap acc 3"    29  (dbAccountExtGap acc3)
    liftIO $ assertEqual "IntGap acc 3"    29  (dbAccountIntGap acc3)

    cmdList "" 0 5 >>= liftIO . assertEqual "check empty addrs 1"
        ( object
            [ "Addresses" .= toJSON ([] :: [Value])
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (5 :: Int)
                , "Total pages" .= (1 :: Int)
                , "Total addresses" .= (0 :: Int)
                ]
            ]
        )

    cmdList "acc1" 0 5 >>= liftIO . assertEqual "check empty addrs 2"
        ( object
            [ "Addresses" .= toJSON ([] :: [Value])
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (5 :: Int)
                , "Total pages" .= (1 :: Int)
                , "Total addresses" .= (0 :: Int)
                ]
            ]
        )

    cmdList "acc2" 0 5 >>= liftIO . assertEqual "check empty addrs 3"
        ( object
            [ "Addresses" .= toJSON ([] :: [Value])
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (5 :: Int)
                , "Total pages" .= (1 :: Int)
                , "Total addresses" .= (0 :: Int)
                ]
            ]
        )
        

testNewMS :: (PersistStore m, PersistUnique m, PersistQuery m) 
          => EitherT String m ()
testNewMS = do 

    -- Creating invalid multisig accounts should fail
    runEitherT (cmdNewMS "ms1" (-1) 0 []) >>= liftIO . assertEqual "Invalid ms 1"
        (Left "cmdNewMS: Invalid multisig parameters")

    -- Creating invalid multisig accounts should fail
    runEitherT (cmdNewMS "ms1" 0 (-1) []) >>= liftIO . assertEqual "Invalid ms 2"
        (Left "cmdNewMS: Invalid multisig parameters")

    -- Creating invalid multisig accounts should fail
    runEitherT (cmdNewMS "ms1" 0 0 []) >>= liftIO . assertEqual "Invalid ms 3"
        (Left "cmdNewMS: Invalid multisig parameters")

    -- Creating invalid multisig accounts should fail
    runEitherT (cmdNewMS "ms1" 0 3 []) >>= liftIO . assertEqual "Invalid ms 4"
        (Left "cmdNewMS: Invalid multisig parameters")

    -- Creating invalid multisig accounts should fail
    runEitherT (cmdNewMS "ms1" 3 0 []) >>= liftIO . assertEqual "Invalid ms 5"
        (Left "cmdNewMS: Invalid multisig parameters")

    -- Creating invalid multisig accounts should fail
    runEitherT (cmdNewMS "ms1" 3 17 []) >>= liftIO . assertEqual "Invalid ms 6"
        (Left "cmdNewMS: Invalid multisig parameters")

    -- Creating invalid multisig accounts should fail
    runEitherT (cmdNewMS "ms1" 17 3 []) >>= liftIO . assertEqual "Invalid ms 7"
        (Left "cmdNewMS: Invalid multisig parameters")

    -- Creating invalid multisig accounts should fail
    runEitherT (cmdNewMS "ms1" 3 2 []) >>= liftIO . assertEqual "Invalid ms 8"
        (Left "cmdNewMS: Invalid multisig parameters")

    -- Create a new 2 of 3 multisig account name "ms1"
    cmdNewMS "ms1" 2 3 [] >>= liftIO . assertEqual "New ms 1" 
        ( object 
            [ "Name" .= T.pack "ms1"
            , "Tree" .= T.pack "m/3'/"
            , "Type" .= T.pack "Multisig 2 of 3"
            , "Warning" .= T.pack "2 multisig keys missing"
            ] 
        )

    -- Check the wallet account index
    (dbWalletAccIndex . entityVal <$> dbGetWallet "main") >>= 
        liftIO . assertEqual "acc index 3" 3

    -- Display account information for account "ms1"
    cmdAccInfo "ms1" >>= liftIO . assertEqual "MS info"
        ( object 
            [ "Name" .= T.pack "ms1"
            , "Tree" .= T.pack "m/3'/"
            , "Type" .= T.pack "Multisig 2 of 3"
            , "Warning" .= T.pack "2 multisig keys missing"
            ] 
        )

    -- List all accounts created up to now (include the "ms1")
    cmdListAcc >>= liftIO . assertEqual "List accs"
        ( toJSON
            [ object 
                [ "Name" .= T.pack ""
                , "Tree" .= T.pack "m/0'/"
                , "Type" .= T.pack "Regular"
                ] 
            , object 
                [ "Name" .= T.pack "acc1"
                , "Tree" .= T.pack "m/1'/"
                , "Type" .= T.pack "Regular"
                ] 
            , object 
                [ "Name" .= T.pack "acc2"
                , "Tree" .= T.pack "m/2'/"
                , "Type" .= T.pack "Regular"
                ] 
            , object 
                [ "Name" .= T.pack "ms1"
                , "Tree" .= T.pack "m/3'/"
                , "Type" .= T.pack "Multisig 2 of 3"
                , "Warning" .= T.pack "2 multisig keys missing"
                ] 
            ]
        )

    -- Initialize some keys for the next tests
    let mstKey = fromJust $ makeMasterKey $ stringToBS "Hello World"
        mstKey2 = fromJust $ makeMasterKey $ stringToBS "Hello World 2"
        prvs = map (getAccPrvKey . fst) $ accPrvKeys mstKey 0
        pubs = map deriveXPubKey prvs
        prvs2 = map (getAccPrvKey . fst) $ accPrvKeys mstKey2 0
        pubs2 = map deriveXPubKey prvs2

    -- Count the number of accounts in the database
    count ([] :: [Filter (DbAccountGeneric b)]) >>= 
        liftIO . assertEqual "MS count" 4

    -- Adding empty key list should fail
    runEitherT (cmdAddKeys "ms1" []) >>= liftIO . assertEqual "Empty addKey"
        (Left "dbAddKeys: Keys can not be empty")

    -- Adding keys to a non-multisig account should fail
    runEitherT (cmdAddKeys "acc1" [pubs !! 0]) >>= 
        liftIO . assertEqual "Invalid addKey 1" 
            (Left "dbAddKeys: Can only add keys to a multisig account")

    -- Adding your own keys to a multisig account should fail
    runEitherT (cmdAddKeys "ms1" [pubs !! 0]) >>=
        liftIO . assertEqual "Invalid addKey 2" 
            (Left "dbAddKeys: Can not add your own keys to a multisig account")

    -- Adding your own keys to a multisig account should fail
    runEitherT (cmdAddKeys "ms1" [pubs2 !! 0,pubs !! 1]) >>=
        liftIO . assertEqual "Invalid addKey 3" 
            (Left "dbAddKeys: Can not add your own keys to a multisig account")
        
    -- Adding too many keys to a multisig account should fail
    runEitherT (cmdAddKeys "ms1" $ take 4 pubs2) >>=
        liftIO . assertEqual "Invalid addKey 4" 
            (Left "dbAddKeys: Too many keys")

    -- Display account information for account "ms1". Shold not have changed
    cmdAccInfo "ms1" >>= liftIO . assertEqual "MS info 2"
        ( object 
            [ "Name" .= T.pack "ms1"
            , "Tree" .= T.pack "m/3'/"
            , "Type" .= T.pack "Multisig 2 of 3"
            , "Warning" .= T.pack "2 multisig keys missing"
            ] 
        )
    
    -- Check that address-related data and gaps are correct
    (Entity a1 acc1) <- dbGetAcc "ms1"

    count [DbAddressAccount ==. a1, DbAddressInternal ==. True] >>=
        liftIO . assertEqual "Int gap address count MS 1" 0

    count [DbAddressAccount ==. a1, DbAddressInternal ==. False] >>=
        liftIO . assertEqual "Ext gap address count MS 1" 0

    liftIO $ assertEqual "ExtIndex acc MS" (-1) (dbAccountExtIndex acc1)
    liftIO $ assertEqual "IntIndex acc MS" (-1) (dbAccountIntIndex acc1)
    liftIO $ assertEqual "ExtGap acc MS"   (-1)  (dbAccountExtGap acc1)
    liftIO $ assertEqual "IntGap acc MS"   (-1)  (dbAccountIntGap acc1)

    cmdList "ms1" 0 5 >>= liftIO . assertEqual "check empty addrs MS 1"
        ( object
            [ "Addresses" .= toJSON ([] :: [Value])
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (5 :: Int)
                , "Total pages" .= (1 :: Int)
                , "Total addresses" .= (0 :: Int)
                ]
            ]
        )

    -- Adding a key to the multisig account "ms1". One should still be missing
    cmdAddKeys "ms1" [pubs2 !! 0] >>= liftIO . assertEqual "MS addkey 1"
        ( object 
            [ "Name" .= T.pack "ms1"
            , "Tree" .= T.pack "m/3'/"
            , "Type" .= T.pack "Multisig 2 of 3"
            , "Warning" .= T.pack "1 multisig keys missing"
            ] 
        )

    -- Dump the keys of account "ms1". One account should be listed under MSKeys
    cmdDumpKeys "ms1" >>= liftIO . assertEqual "MS dumpkey 2" 
        ( object 
            [ "Account" .= object 
                [ "Name" .= T.pack "ms1"
                , "Tree" .= T.pack "m/3'/"
                , "Type" .= T.pack "Multisig 2 of 3"
                , "Warning" .= T.pack "1 multisig keys missing"
                ] 
            , "PubKey"  .= (xPubExport $ pubs !! 3)
            , "PrvKey"  .= (xPrvExport $ prvs !! 3)
            , "MSKeys"  .= toJSON [xPubExport $ pubs2 !! 0]
            ]
        )

    -- Check that address-related data and gaps are correct
    (Entity a2 acc2) <- dbGetAcc "ms1"

    count [DbAddressAccount ==. a2, DbAddressInternal ==. True] >>=
        liftIO . assertEqual "Int gap address count MS 2" 0

    count [DbAddressAccount ==. a2, DbAddressInternal ==. False] >>=
        liftIO . assertEqual "Ext gap address count MS 2" 0

    liftIO $ assertEqual "ExtIndex acc MS 2" (-1) (dbAccountExtIndex acc2)
    liftIO $ assertEqual "IntIndex acc MS 2" (-1) (dbAccountIntIndex acc2)
    liftIO $ assertEqual "ExtGap acc MS 2"   (-1)  (dbAccountExtGap acc2)
    liftIO $ assertEqual "IntGap acc MS 2"   (-1)  (dbAccountIntGap acc2)

    cmdList "ms1" 0 5 >>= liftIO . assertEqual "check empty addrs MS 2"
        ( object
            [ "Addresses" .= toJSON ([] :: [Value])
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (5 :: Int)
                , "Total pages" .= (1 :: Int)
                , "Total addresses" .= (0 :: Int)
                ]
            ]
        )

    -- Add second key to account "ms1". Account should be complete now
    cmdAddKeys "ms1" [pubs2 !! 1] >>= liftIO . assertEqual "MS addkey 2" 
        ( object 
            [ "Name" .= T.pack "ms1"
            , "Tree" .= T.pack "m/3'/"
            , "Type" .= T.pack "Multisig 2 of 3"
            ] 
        )

    -- Dumping "ms1" keys should now display all keys
    cmdDumpKeys "ms1" >>= liftIO . assertEqual "MS dumpkey 2" 
        ( object 
            [ "Account" .= object 
                [ "Name" .= T.pack "ms1"
                , "Tree" .= T.pack "m/3'/"
                , "Type" .= T.pack "Multisig 2 of 3"
                ] 
            , "PubKey"  .= (xPubExport $ pubs !! 3)
            , "PrvKey"  .= (xPrvExport $ prvs !! 3)
            , "MSKeys"  .= toJSON [ xPubExport $ pubs2 !! 0
                                  , xPubExport $ pubs2 !! 1
                                  ]
            ]
        )

    -- Check that address-related data and gaps are correct
    (Entity a3 acc3) <- dbGetAcc "ms1"

    count [DbAddressAccount ==. a3, DbAddressInternal ==. True] >>=
        liftIO . assertEqual "Int gap address count MS 3" 30

    count [DbAddressAccount ==. a3, DbAddressInternal ==. False] >>=
        liftIO . assertEqual "Ext gap address count MS 3" 30

    liftIO $ assertEqual "ExtIndex acc MS 3" (-1) (dbAccountExtIndex acc3)
    liftIO $ assertEqual "IntIndex acc MS 3" (-1) (dbAccountIntIndex acc3)
    liftIO $ assertEqual "ExtGap acc MS 3"    29  (dbAccountExtGap acc3)
    liftIO $ assertEqual "IntGap acc MS 3"    29  (dbAccountIntGap acc3)

    cmdList "ms1" 0 5 >>= liftIO . assertEqual "check empty addrs MS 3"
        ( object
            [ "Addresses" .= toJSON ([] :: [Value])
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (5 :: Int)
                , "Total pages" .= (1 :: Int)
                , "Total addresses" .= (0 :: Int)
                ]
            ]
        )

    -- Adding another key now should fail as the account "ms1" is complete
    runEitherT (cmdAddKeys "ms1" [pubs2 !! 2]) >>=
        liftIO . assertEqual "Invalid addKey 5" 
            (Left "dbAddKeys: Account is complete. No more keys can be added")

testGenAddr :: (PersistStore m, PersistUnique m, PersistQuery m) 
          => EitherT String m ()
testGenAddr = do 

    -- List addresses from an empty account
    cmdList "" 0 5 >>= liftIO . assertEqual "list empty addr" 
        ( object
            [ "Addresses" .= toJSON ([] :: [Value])
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (5 :: Int)
                , "Total pages" .= (1 :: Int)
                , "Total addresses" .= (0 :: Int)
                ]
            ]
        )

    -- Generate 5 addresses on the account "" (empty string)
    cmdGenAddrs "" 5 >>= liftIO . assertEqual "gen addr"
        ( toJSON 
            [ object [ "Addr" .= T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                     , "Key"  .= (0 :: Int)
                     , "Tree" .= T.pack "m/0'/0/0/"
                     ]
            , object [ "Addr" .= T.pack "1NkXvbrHPGC2vjtmL2mup1sWi2TU8LW6XB"
                     , "Key"  .= (1 :: Int)
                     , "Tree" .= T.pack "m/0'/0/1/"
                     ]
            , object [ "Addr" .= T.pack "1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY"
                     , "Key"  .= (2 :: Int)
                     , "Tree" .= T.pack "m/0'/0/2/"
                     ]
            , object [ "Addr" .= T.pack "1Erwcuqn1dHm8r6fNxogGmCHYuNfwKNwer"
                     , "Key"  .= (3 :: Int)
                     , "Tree" .= T.pack "m/0'/0/3/"
                     ]
            , object [ "Addr" .= T.pack "18aT8MJ15VV26nx29xmbu5fzvqE6sqh6i9"
                     , "Key"  .= (4 :: Int)
                     , "Tree" .= T.pack "m/0'/0/4/"
                     ]
            ]
        )

    -- Check account external index
    (dbAccountExtIndex . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc ext index" 4

    -- Check account internal index
    (dbAccountIntIndex . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc int index" (-1)

    -- Check account external gap
    (dbAccountExtGap . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc ext gap" 34

    -- Check account internal gap
    (dbAccountIntGap . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc int gap" 29

    -- Count all addresses in the Address table
    -- 60*4 + 5
    count ([] :: [Filter (DbAddressGeneric b)]) >>= 
        liftIO . assertEqual "Count addr" 245

    let f x = (dbAddressBase58 x,dbAddressTree x,dbAddressIndex x)
    (map f <$> dbGenIntAddrs "" 4) >>= liftIO . assertEqual "Internal addr"
        [ ("19RtLtmuuxscgg5TXkCsSJ7bCdEzci5XTm","m/0'/1/0/",0)
        , ("1E75f3kuDanTHeTa8nvJCxYF8MXaud4QPE","m/0'/1/1/",1)
        , ("1NXkqUpqM23p6u44nAhoP1wVd2BdCEr4Zm","m/0'/1/2/",2)
        , ("1AjBQfprusZGGnD4jCmexizJxKBcAw4cdc","m/0'/1/3/",3)
        ]

    -- Check account external index
    (dbAccountExtIndex . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc ext index 2" 4

    -- Check account internal index
    (dbAccountIntIndex . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc int index" 3

    -- Check account external gap
    (dbAccountExtGap . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc ext gap" 34

    -- Check account internal gap
    (dbAccountIntGap . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc int gap" 33

    -- Count all addresses in the Address table
    -- 60*4 + 5
    count ([] :: [Filter (DbAddressGeneric b)]) >>= 
        liftIO . assertEqual "Count addr" 249

    -- List addresses from the ms1 account. Should be empty
    cmdList "ms1" 0 5 >>= liftIO . assertEqual "list empty addr 2"
        ( object
            [ "Addresses" .= toJSON ([] :: [Value])
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (5 :: Int)
                , "Total pages" .= (1 :: Int)
                , "Total addresses" .= (0 :: Int)
                ]
            ]
        )

    -- List page 1 with 1 result per page
    cmdList "" 1 1 >>= liftIO . assertEqual "list addr 1"
        ( object 
            [ "Addresses" .= toJSON 
                [ object [ "Addr" .= T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                         , "Key"  .= (0 :: Int)
                         , "Tree" .= T.pack "m/0'/0/0/"
                         ]
                ]
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (1 :: Int)
                , "Total pages" .= (5 :: Int)
                , "Total addresses" .= (5 :: Int)
                ]
            ]
        )

    -- List page 2 with 1 result per page
    cmdList "" 2 1 >>= liftIO . assertEqual "list addr 2"
        ( object 
            [ "Addresses" .= toJSON 
               [ object [ "Addr" .= T.pack "1NkXvbrHPGC2vjtmL2mup1sWi2TU8LW6XB"
                        , "Key"  .= (1 :: Int)
                        , "Tree" .= T.pack "m/0'/0/1/"
                        ]
               ]
            , "Page results" .= object
                [ "Current page" .= (2 :: Int)
                , "Results per page" .= (1 :: Int)
                , "Total pages" .= (5 :: Int)
                , "Total addresses" .= (5 :: Int)
                ]
            ]
        )

    -- List page 0 (last page) with 1 result per page
    cmdList "" 0 1 >>= liftIO . assertEqual "list addr 2"
        ( object 
            [ "Addresses" .= toJSON 
               [ object [ "Addr" .= T.pack "18aT8MJ15VV26nx29xmbu5fzvqE6sqh6i9"
                        , "Key"  .= (4 :: Int)
                        , "Tree" .= T.pack "m/0'/0/4/"
                        ]
               ]
            , "Page results" .= object
                [ "Current page" .= (5 :: Int)
                , "Results per page" .= (1 :: Int)
                , "Total pages" .= (5 :: Int)
                , "Total addresses" .= (5 :: Int)
                ]
            ]
        )

    -- Listing page > maxpage should fail
    runEitherT (cmdList "" 6 1) >>= liftIO . assertEqual "list addr 2"
        (Left "cmdList: Page number too high")

    -- List page 0 (last page) with 3 result per page
    cmdList "" 0 3 >>= liftIO . assertEqual "list addr 2"
        ( object 
            [ "Addresses" .= toJSON 
                [ object [ "Addr" .= T.pack "1Erwcuqn1dHm8r6fNxogGmCHYuNfwKNwer"
                         , "Key"  .= (3 :: Int)
                         , "Tree" .= T.pack "m/0'/0/3/"
                         ]
                , object [ "Addr" .= T.pack "18aT8MJ15VV26nx29xmbu5fzvqE6sqh6i9"
                         , "Key"  .= (4 :: Int)
                         , "Tree" .= T.pack "m/0'/0/4/"
                         ]
                ]
            , "Page results" .= object
                [ "Current page" .= (2 :: Int)
                , "Results per page" .= (3 :: Int)
                , "Total pages" .= (2 :: Int)
                , "Total addresses" .= (5 :: Int)
                ]
            ]
        )

    -- Generating multisig addresses with labels
    cmdGenWithLabel "ms1" ["","addr1","addr2","Two Words"] >>= 
        liftIO . assertEqual "gen ms addr" 
        ( toJSON 
            [ object [ "Addr" .= T.pack "32VCGK4pbvVsFvSGfmLpmNTu4JjhuR3WmM"
                     , "Key"  .= (0 :: Int)
                     , "Tree" .= T.pack "m/3'/0/0/"
                     ]
            , object [ "Addr"  .= T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                     , "Key"   .= (1 :: Int)
                     , "Tree"  .= T.pack "m/3'/0/1/"
                     , "Label" .= T.pack "addr1"
                     ]
            , object [ "Addr"  .= T.pack "3E3qvGPki6sypXdyL6CMxBQwzFkY7iKrGW"
                     , "Key"   .= (2 :: Int)
                     , "Tree"  .= T.pack "m/3'/0/2/"
                     , "Label" .= T.pack "addr2"
                     ]
            , object [ "Addr"  .= T.pack "3QqkesBZx7WBSLcdy5e1PmRU1QLdYTG49Q"
                     , "Key"   .= (3 :: Int)
                     , "Tree"  .= T.pack "m/3'/0/3/"
                     , "Label" .= T.pack "Two Words"
                     ]
            ]
        )

    -- Check account external index
    (dbAccountExtIndex . entityVal <$> dbGetAcc "ms1") >>= 
        liftIO . assertEqual "acc ext index 3" 3

    -- Check account internal index
    (dbAccountIntIndex . entityVal <$> dbGetAcc "ms1") >>= 
        liftIO . assertEqual "acc int index 3" (-1)

    -- Check account external gap
    (dbAccountExtGap . entityVal <$> dbGetAcc "ms1") >>= 
        liftIO . assertEqual "acc ext gap 3" 33

    -- Check account internal gap
    (dbAccountIntGap . entityVal <$> dbGetAcc "ms1") >>= 
        liftIO . assertEqual "acc int gap 3" 29

    -- Count addresses
    count ([] :: [Filter (DbAddressGeneric b)]) >>= 
        liftIO . assertEqual "Count addr 3" 253

    let h x = (dbAddressBase58 x,dbAddressTree x,dbAddressIndex x)
    (map h <$> dbGenIntAddrs "ms1" 6) >>= liftIO . assertEqual "Internal addr 2"
        [ ("34rWmp9DmxFbqXLHvzhMGATWDfsnLF8wiR","m/3'/1/0/",0)
        , ("3As9nWqHcWavv3MxSeZKYjMQ9SgE8zVaJ1","m/3'/1/1/",1)
        , ("3QYVvQrjtK5w8s6uE8T8ZLeXBEe7aTtVdj","m/3'/1/2/",2)
        , ("3GS2h9uZ3akS9GQbXDGZtWgAvzLFnjWrsS","m/3'/1/3/",3)
        , ("3CAF8PpJirGsqTxzK2aPao2MQSGkiC3gPN","m/3'/1/4/",4)
        , ("3Kcd2Nz1XYv25U6xUzjAycVBz9rp6r2Tf2","m/3'/1/5/",5)
        ]

    -- Check account external index
    (dbAccountExtIndex . entityVal <$> dbGetAcc "ms1") >>= 
        liftIO . assertEqual "acc ext index 4" 3

    -- Check account internal index
    (dbAccountIntIndex . entityVal <$> dbGetAcc "ms1") >>= 
        liftIO . assertEqual "acc int index 4" 5

    -- Check account external gap
    (dbAccountExtGap . entityVal <$> dbGetAcc "ms1") >>= 
        liftIO . assertEqual "acc ext gap 4" 33

    -- Check account internal gap
    (dbAccountIntGap . entityVal <$> dbGetAcc "ms1") >>= 
        liftIO . assertEqual "acc int gap 4" 35

    -- Count addresses
    count ([] :: [Filter (DbAddressGeneric b)]) >>= 
        liftIO . assertEqual "Count addr 4" 259

    -- Rename the first multisig address label
    cmdLabel "ms1" 0 "alpha" >>= liftIO . assertEqual "label ms"
        ( object 
            [ "Addr"  .= T.pack "32VCGK4pbvVsFvSGfmLpmNTu4JjhuR3WmM"
            , "Key"   .= (0 :: Int)
            , "Tree"  .= T.pack "m/3'/0/0/"
            , "Label" .= T.pack "alpha"
            ]
        )

    -- Rename the last multisig address label
    _ <- cmdLabel "ms1" 3 "beta"

    -- Setting a label on an invalid address should fail
    runEitherT (cmdLabel "ms1" (-1) "theta") >>= 
        liftIO . assertEqual "set label fail"
            (Left "cmdLabel: Key -1 does not exist")

    -- Setting a label on an invalid address should fail
    runEitherT (cmdLabel "ms1" 4 "theta") >>= 
        liftIO . assertEqual "set label fail 2"
            (Left "cmdLabel: Key 4 does not exist")

    -- Setting a label on an invalid address should fail
    runEitherT (cmdLabel "ms1" 100 "theta") >>= 
        liftIO . assertEqual "set label fail 3"
            (Left "cmdLabel: Key 100 does not exist")

    -- List page 1 with 5 result per page
    cmdList "ms1" 1 5 >>= liftIO . assertEqual "list ms"
        ( object 
            [ "Addresses" .= toJSON 
               [ object [ "Addr" .= T.pack "32VCGK4pbvVsFvSGfmLpmNTu4JjhuR3WmM"
                        , "Key"  .= (0 :: Int)
                        , "Tree" .= T.pack "m/3'/0/0/"
                        , "Label" .= T.pack "alpha"
                        ]
               , object [ "Addr"  .= T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                        , "Key"   .= (1 :: Int)
                        , "Tree"  .= T.pack "m/3'/0/1/"
                        , "Label" .= T.pack "addr1"
                        ]
               , object [ "Addr"  .= T.pack "3E3qvGPki6sypXdyL6CMxBQwzFkY7iKrGW"
                        , "Key"   .= (2 :: Int)
                        , "Tree"  .= T.pack "m/3'/0/2/"
                        , "Label" .= T.pack "addr2"
                        ]
               , object [ "Addr"  .= T.pack "3QqkesBZx7WBSLcdy5e1PmRU1QLdYTG49Q"
                        , "Key"   .= (3 :: Int)
                        , "Tree"  .= T.pack "m/3'/0/3/"
                        , "Label" .= T.pack "beta"
                        ]
               ]
            , "Page results" .= object
                [ "Current page" .= (1 :: Int)
                , "Results per page" .= (5 :: Int)
                , "Total pages" .= (1 :: Int)
                , "Total addresses" .= (4 :: Int)
                ]
            ]
        )

{- Payments sent to:
 - 1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi:100000 (in wallet)
 - 1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY:200000 (in wallet)
 - 1Azso1Fz77buNc8p7sm3myVXZxqwQopMtp:240000 (not in wallet)
 - 1L1ryKs82ucjNmGwKT9kAsxeSVX1mhJyo5:122000 (not in wallet)
 - 38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki:150000 (in wallet)
 - 3QqkesBZx7WBSLcdy5e1PmRU1QLdYTG49Q:400000 (in wallet)
 -}

-- ID: a156f308b7c3dab42d98729fefc3dfa944d84f3ac48c7e603a58885d2b34a996
tx1 :: String
tx1 = "01000000010000000000000000000000000000000000000000000000000000000000000001010000006b483045022100bf1c6e0720284bcefa2e104b5eea27fb3f11a8ebce1d7c06a99567473f9524a202201ed0baafcac25f9aa3c81fb26a3476f559169f4c7f5a64e43a2eebb6b0a1aae001210290a14bce9d363667574a29da1b2e38d106968969f449588713bb271e28a9a4a0ffffffff06a0860100000000001976a914d6baf45f52b4cccc7ac1ba3a35dd739497f8e98988ac400d0300000000001976a91468e94ed1e88f7e942bf4aaa25fcf5930f517730888ac80a90300000000001976a9146dab3dec58a7ab13267c4ec8c60b516cbe7a3c9f88ac90dc0100000000001976a914d0941a8b2ce829d8692bf6af24f67c485ff9a20b88acf04902000000000017a9144d769c08d79eed22532e044213bef3174f05158487801a06000000000017a914fdf1e3c1a936ab1dde0d7a305d28df396949ffd08700000000"

-- ID: 319f26fb4638f038008e3a9da98177f7a7cfaee64bab77328cf69e39c7fce785
tx2 :: String
tx2 = "01000000010000000000000000000000000000000000000000000000000000000000000002010000006b483045022100bf1c6e0720284bcefa2e104b5eea27fb3f11a8ebce1d7c06a99567473f9524a202201ed0baafcac25f9aa3c81fb26a3476f559169f4c7f5a64e43a2eebb6b0a1aae001210290a14bce9d363667574a29da1b2e38d106968969f449588713bb271e28a9a4a0ffffffff06a0860100000000001976a914d6baf45f52b4cccc7ac1ba3a35dd739497f8e98988ac400d0300000000001976a91468e94ed1e88f7e942bf4aaa25fcf5930f517730888ac80a90300000000001976a9146dab3dec58a7ab13267c4ec8c60b516cbe7a3c9f88ac90dc0100000000001976a914d0941a8b2ce829d8692bf6af24f67c485ff9a20b88acf04902000000000017a9144d769c08d79eed22532e044213bef3174f05158487801a06000000000017a914fdf1e3c1a936ab1dde0d7a305d28df396949ffd08700000000"

testImport :: ( PersistStore m, PersistUnique m, PersistQuery m
              , PersistMonadBackend m ~ SqlBackend
              ) 
           => EitherT String m ()
testImport = do 

    -- Importin transaction sending funds to two different accounts
    cmdImportTx (decode' $ fromJust $ hexToBS tx1) >>= 
        liftIO . assertEqual "Import tx 1"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                             , T.pack "1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY"
                             ]
                         , "Value"      .= (300000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                             , T.pack "3QqkesBZx7WBSLcdy5e1PmRU1QLdYTG49Q"
                             ]
                         , "Value"      .= (550000 :: Int)
                         ]
                ]
            )

    -- Importin similar transaction sending funds to two different accounts
    cmdImportTx (decode' $ fromJust $ hexToBS tx2) >>= 
        liftIO . assertEqual "Import tx 2"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                             , T.pack "1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY"
                             ]
                         , "Value"      .= (300000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                             , T.pack "3QqkesBZx7WBSLcdy5e1PmRU1QLdYTG49Q"
                             ]
                         , "Value"      .= (550000 :: Int)
                         ]
                ]
            )

    -- List transactions of account ""
    cmdListTx "" >>= liftIO . assertEqual "List tx 1"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                            [ T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                            , T.pack "1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY"
                            ]
                        , "Value"      .= (300000 :: Int)
                        ]
            , object [ "Recipients" .= toJSON
                            [ T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                            , T.pack "1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY"
                            ]
                        , "Value"      .= (300000 :: Int)
                        ]
            ]
        )

    -- List transactions of account "ms1"
    cmdListTx "ms1" >>= liftIO . assertEqual "List tx 2"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                         , T.pack "3QqkesBZx7WBSLcdy5e1PmRU1QLdYTG49Q"
                         ]
                     , "Value"      .= (550000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                         , T.pack "3QqkesBZx7WBSLcdy5e1PmRU1QLdYTG49Q"
                         ]
                     , "Value"      .= (550000 :: Int)
                     ]
            ]
        )

    -- Verify the balance of account ""
    cmdBalance "" >>= liftIO . assertEqual "Balance 1" 
        (object ["Balance" .= (600000 :: Int)])

    -- Verify the balance of account "ms1"
    cmdBalance "ms1" >>= liftIO . assertEqual "Balance 2" 
        (object ["Balance" .= (1100000 :: Int)])

    -- Get coins of account ""
    cmdCoins "" >>= liftIO . assertEqual "Get coins 1"
        ( toJSON
            [ object
                [ "TxID"    .= T.pack "a156f308b7c3dab42d98729fefc3dfa944d84f3ac48c7e603a58885d2b34a996"
                , "Index"   .= (0 :: Int)
                , "Value"   .= (100000 :: Int)
                , "Script"  .= T.pack "76a914d6baf45f52b4cccc7ac1ba3a35dd739497f8e98988ac"
                , "Address" .= T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                ]
            , object
                [ "TxID"    .= T.pack "a156f308b7c3dab42d98729fefc3dfa944d84f3ac48c7e603a58885d2b34a996"
                , "Index"   .= (1 :: Int)
                , "Value"   .= (200000 :: Int)
                , "Script"  .= T.pack "76a91468e94ed1e88f7e942bf4aaa25fcf5930f517730888ac"
                , "Address" .= T.pack "1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY"
                ]
            , object
                [ "TxID"    .= T.pack "319f26fb4638f038008e3a9da98177f7a7cfaee64bab77328cf69e39c7fce785"
                , "Index"   .= (0 :: Int)
                , "Value"   .= (100000 :: Int)
                , "Script"  .= T.pack "76a914d6baf45f52b4cccc7ac1ba3a35dd739497f8e98988ac"
                , "Address" .= T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                ]
            , object
                [ "TxID"    .= T.pack "319f26fb4638f038008e3a9da98177f7a7cfaee64bab77328cf69e39c7fce785"
                , "Index"   .= (1 :: Int)
                , "Value"   .= (200000 :: Int)
                , "Script"  .= T.pack "76a91468e94ed1e88f7e942bf4aaa25fcf5930f517730888ac"
                , "Address" .= T.pack "1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY"
                ]
            ]
        )

    -- Get coins of account "ms1"
    cmdCoins "ms1" >>= liftIO . assertEqual "Get coins 2"
        ( toJSON
            [ object
                [ "TxID"   .= T.pack "a156f308b7c3dab42d98729fefc3dfa944d84f3ac48c7e603a58885d2b34a996"
                , "Index"   .= (4 :: Int)
                , "Value"   .= (150000 :: Int)
                , "Script"  .= T.pack "a9144d769c08d79eed22532e044213bef3174f05158487"
                , "Redeem"  .= T.pack "5221026e294fcecdcbae12a0aba1685db35c54ddfc1375d48f96ff1b8805a4bb57bfc921028bc8d8377f44de8ac8beff0dc9ccefde4cd5dded7b8cd8babe02c7147a90ba6c21039cf5d06e79871043c420fabc652f8082e702e0094f91ec14c020e9fcf48fa4d853ae"
                , "Address" .= T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                ]
            , object
                [ "TxID"   .= T.pack "a156f308b7c3dab42d98729fefc3dfa944d84f3ac48c7e603a58885d2b34a996"
                , "Index"   .= (5 :: Int)
                , "Value"   .= (400000 :: Int)
                , "Script"  .= T.pack "a914fdf1e3c1a936ab1dde0d7a305d28df396949ffd087"
                , "Redeem"  .= T.pack "5221020f7ead178316e8414d128712a23cde2e843d1a0f66afc0bfa600ab90deefd5f321023182b240cb2607ed03f76c9dca37c4b9fcb3b763b776223cc94808f7e67fb03a2102648dbcbc9f44fb55a992efe7b3ab214306cc72cdcae2a7cf6f9d44262a53c3b353ae"
                , "Address" .= T.pack "3QqkesBZx7WBSLcdy5e1PmRU1QLdYTG49Q"
                ]
            , object
                [ "TxID"   .= T.pack "319f26fb4638f038008e3a9da98177f7a7cfaee64bab77328cf69e39c7fce785"
                , "Index"   .= (4 :: Int)
                , "Value"   .= (150000 :: Int)
                , "Script"  .= T.pack "a9144d769c08d79eed22532e044213bef3174f05158487"
                , "Redeem"  .= T.pack "5221026e294fcecdcbae12a0aba1685db35c54ddfc1375d48f96ff1b8805a4bb57bfc921028bc8d8377f44de8ac8beff0dc9ccefde4cd5dded7b8cd8babe02c7147a90ba6c21039cf5d06e79871043c420fabc652f8082e702e0094f91ec14c020e9fcf48fa4d853ae"
                , "Address" .= T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                ]
            , object
                [ "TxID"   .= T.pack "319f26fb4638f038008e3a9da98177f7a7cfaee64bab77328cf69e39c7fce785"
                , "Index"   .= (5 :: Int)
                , "Value"   .= (400000 :: Int)
                , "Script"  .= T.pack "a914fdf1e3c1a936ab1dde0d7a305d28df396949ffd087"
                , "Redeem"  .= T.pack "5221020f7ead178316e8414d128712a23cde2e843d1a0f66afc0bfa600ab90deefd5f321023182b240cb2607ed03f76c9dca37c4b9fcb3b763b776223cc94808f7e67fb03a2102648dbcbc9f44fb55a992efe7b3ab214306cc72cdcae2a7cf6f9d44262a53c3b353ae"
                , "Address" .= T.pack "3QqkesBZx7WBSLcdy5e1PmRU1QLdYTG49Q"
                ]
            ]
        )

    -- ID: 9062c5ae9a4e84e37e712387a111f2dba6be57de4235df8dd1fae67cc2071771
    -- Input: 200000 and 200000 = 400000
    -- Output = 340000 + 50000 change = 390000
    -- Fee = 10000

    let txRes = "010000000285e7fcc7399ef68c3277ab4be6aecfa7f77781a99d3a8e0038f03846fb269f31010000006a47304402200f4bc4dba8e47e810362d48502329a75624d8863d8bd22618bd47c5fff8bd9e402200531318470a60b4d898b2061c3eef96ad9129ca758e7f55bd120a81569a7196201210250f4e42bb94ed8b27c6c8b728c0bd02828af1d4ebf8e3f0a6e7da3f53369c104ffffffff96a9342b5d88583a607e8cc43a4fd844a9dfc3ef9f72982db4dac3b708f356a1010000006a4730440220566d57667786d93551976f2bf890de9d623820c02c2e6d4476a71c27b771eae6022004227d27972a1f0933bf50472d85644cc5dbbc277f1370c171f80e95ed834ca401210250f4e42bb94ed8b27c6c8b728c0bd02828af1d4ebf8e3f0a6e7da3f53369c104ffffffff04c0d401000000000017a9144d769c08d79eed22532e044213bef3174f0515848780380100000000001976a914980b9c708958bbe4cc05d0b302d4f12625a5d88c88ace0220200000000001976a9147f77d7a91f8e53a387530c58139290211579dd2b88ac50c30000000000001976a914bb498fb0f0d0639193660b40a9a91e1b3eb60bab88ac00000000"

    cmdSendMany "" 
        [ ("38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki",120000) -- In wallet
        , ("1Erwcuqn1dHm8r6fNxogGmCHYuNfwKNwer", 80000) -- In wallet
        , ("1CczPAHXrwyiCeJfx5Bifaoo4NBQr3TPpJ",140000) -- Not in wallet
        ] 10000 >>= liftIO . assertEqual "sendMany tx"
            (object 
               [ "Tx" .= T.pack txRes
               , "Complete" .= True
               ]
            )

    -- Check that the internal change address was correctly generated
    (dbAddressIndex . entityVal) <$> 
        (dbGetAddr "1J5HV12wGbPj5SUryku2zFoaxnC1AngqcH") >>= 
            liftIO . assertEqual "check internal address" 4

    (dbAddressTree . entityVal) <$> 
        (dbGetAddr "1J5HV12wGbPj5SUryku2zFoaxnC1AngqcH") >>= 
            liftIO . assertEqual "check internal address tree" "m/0'/1/4/"

    (dbAddressInternal . entityVal) <$> 
        (dbGetAddr "1J5HV12wGbPj5SUryku2zFoaxnC1AngqcH") >>= 
            liftIO . assertEqual "check internal address tree" True

    -- Check account external index
    (dbAccountExtIndex . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc ext index 5" 4

    -- Check account internal index
    (dbAccountIntIndex . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc int index 5" 4

    -- Check account external gap
    (dbAccountExtGap . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc ext gap 5" 34

    -- Check account internal gap
    (dbAccountIntGap . entityVal <$> dbGetAcc "") >>= 
        liftIO . assertEqual "acc int gap 5" 34

    -- Count addresses
    count ([] :: [Filter (DbAddressGeneric b)]) >>= 
        liftIO . assertEqual "Count addr 5" 260


    (cmdImportTx $ decode' $ fromJust $ hexToBS txRes) >>=
        liftIO . assertEqual "import send tx"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                             , T.pack "1CczPAHXrwyiCeJfx5Bifaoo4NBQr3TPpJ"
                             ]
                         , "Value"      .= (-270000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki" ]
                         , "Value"      .= (120000 :: Int)
                         ]
                ]
            )

    -- Get coins of account ""
    cmdCoins "" >>= liftIO . assertEqual "Get coins 2"
        ( toJSON
            [ object
                [ "TxID"    .= T.pack "a156f308b7c3dab42d98729fefc3dfa944d84f3ac48c7e603a58885d2b34a996"
                , "Index"   .= (0 :: Int)
                , "Value"   .= (100000 :: Int)
                , "Script"  .= T.pack "76a914d6baf45f52b4cccc7ac1ba3a35dd739497f8e98988ac"
                , "Address" .= T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                ]
            , object
                [ "TxID"    .= T.pack "319f26fb4638f038008e3a9da98177f7a7cfaee64bab77328cf69e39c7fce785"
                , "Index"   .= (0 :: Int)
                , "Value"   .= (100000 :: Int)
                , "Script"  .= T.pack "76a914d6baf45f52b4cccc7ac1ba3a35dd739497f8e98988ac"
                , "Address" .= T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                ]
            , object
                [ "TxID"    .= T.pack "9062c5ae9a4e84e37e712387a111f2dba6be57de4235df8dd1fae67cc2071771"
                , "Index"   .= (1 :: Int)
                , "Value"   .= (80000 :: Int)
                , "Script"  .= T.pack "76a914980b9c708958bbe4cc05d0b302d4f12625a5d88c88ac"
                , "Address" .= T.pack "1Erwcuqn1dHm8r6fNxogGmCHYuNfwKNwer"
                ]
            , object
                [ "TxID"    .= T.pack "9062c5ae9a4e84e37e712387a111f2dba6be57de4235df8dd1fae67cc2071771"
                , "Index"   .= (3 :: Int)
                , "Value"   .= (50000 :: Int)
                , "Script"  .= T.pack "76a914bb498fb0f0d0639193660b40a9a91e1b3eb60bab88ac"
                , "Address" .= T.pack "1J5HV12wGbPj5SUryku2zFoaxnC1AngqcH"
                ]
            ]
        )

    -- List transactions of account ""
    cmdListTx "" >>= liftIO . assertEqual "List tx 2"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                         , T.pack "1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY"
                         ]
                     , "Value"      .= (300000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "1LaPZtFWAWRP8eLNZRLLPGaB3dn19Nb6wi"
                         , T.pack "1AZimU5FfTQyF4GMsEKLZ32773TtPKczdY"
                         ]
                     , "Value"      .= (300000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "38kc3Sw4fwkvXMyGPmjQqp7WXMdGQG3Lki"
                         , T.pack "1CczPAHXrwyiCeJfx5Bifaoo4NBQr3TPpJ"
                         ]
                     , "Value"      .= (-270000 :: Int)
                     ]
            ]
        )
            
    -- Verify the balance of account ""
    cmdBalance "" >>= liftIO . assertEqual "Balance 3" 
        (object ["Balance" .= (330000 :: Int)])

    -- Verify the balance of account "ms1"
    cmdBalance "ms1" >>= liftIO . assertEqual "Balance 4" 
        (object ["Balance" .= (1220000 :: Int)])

-- Building tx link:
-- txA : outside => acc1
-- txB : acc1 => (acc1,acc2,outside)
-- txC : acc2 => (acc1,outside) 
-- tcD : acc1 => outside
-- import order: txC, tcB, txA

{- TxID: 23c5dcac6ef51d36ca63cf7f3dc30163939bb208eb8e12b92183ccc1333c20bd
 - Payments sent to:
 - 1ChqhDvLVx5bjRHbdUweCsd4mgwD4fvdGL : 100000 (acc1)
 - 1DKe1dvRznGqmBFsHY7MmvJy3DtcfBDZbw : 200000 (acc1)
 - 17yJQpBHpWyVHNshgGpCK876Nb8qqvp3rG : 300000 (acc1)
 -}

txA :: String
txA = "01000000010000000000000000000000000000000000000000000000000000000000000001090000006a4730440220464686ba44f82d76bc3687399f971fe86661241b9698308711e099fab785ef140220074de9e525ae379fc7ab676fbeb475e7c8aa7268afb0c3f48ea18137bf069f7d01210290a14bce9d363667574a29da1b2e38d106968969f449588713bb271e28a9a4a0ffffffff03a0860100000000001976a9148062ab5c3fdf5f8f0d41fccacbb3ea8058b911ae88ac400d0300000000001976a9148727e4552058a555d0ce269d8cf8c850785666f688ace0930400000000001976a9144c769509bb3e22c2275cd025fcb55ebc5dc1e39f88ac00000000"

{- TxID: 53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0
 - inputs: acc1 (index 1 and index 2 = 500000)
 - Payments sent to:
 - 14JcRDidCbYFBwWjP9PGJL1MRKCzUWCmaS : 100000 (acc1)
 - 16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M : 200000 (acc2)
 - 1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86 : 150000 (outside)
 - 1Baez98Lapiu7mQLfXuUCjBreEAwFrWNd2 :  40000 (change to acc1)
 -}

txB :: String
txB = "0100000002bd203c33c1cc8321b9128eeb08b29b936301c33d7fcf63ca361df56eacdcc523010000006b4830450221009c061ca53ccfdd379f883857466103308f54c764e7acd94f5eb23d40bb5ce1cc022074f40ed51bbdc295307db177c15679939e104bcc8944b54eb3ac681992f27a10012103a40f6bd1d59440a007aa8ec93875d07f234ffebe76df311c1b610fc1c0d22dd9ffffffffbd203c33c1cc8321b9128eeb08b29b936301c33d7fcf63ca361df56eacdcc523020000006a47304402204e3c85a423066ef44a7d25d0ee0352d8dd5e7628e989aa9f0833abe681405610022030638452839cbb210bf7589e16beb0a737ecbc4a6560e28cd3b11517c83ff225012103a0d2cdf936eca39cfd6407393f8f0f2af932bdea6271d559308075b77d2ec080ffffffff04a0860100000000001976a914243d03889d49470ee721d44596fd146440e1167c88ac400d0300000000001976a9143f53fba59a1c17f17cf3c4b5cfcf15fa0087f1c188acf0490200000000001976a9149d3e18f3cd8edf442c31cb5cc5b0acf8e4e96a1e88ac409c0000000000001976a914740eb168ae243882a73f5467b9024431443ef12988ac00000000"

{- TxID: 2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150
 - inputs: acc2 (index 1 = 200000)
 - Payments sent to:
 - 14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb : 120000 (acc1)
 - 13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n :  40000 (outside)
 - 13wD1L9PvEgBytP5X6ykiuhB8gRP58CB5J :  30000 (change to acc2)
 -}

txC :: String
txC = "0100000001d0a3cbf9246be9519374c96b551545050b01d53c9d33e2ff3af59e571411fe53010000006b483045022100ff41f0cb1ce0f7f6d07b93c9f3c43480f843092a14618b2b20c2fad90d003216022049069460cbf2355f03ed31ac25cc086057aa752bd53f9de558f33e565369d11e012103b4b925d5967a00d2540115f035aa10290853d39e3c20591d711680cac5e2b4efffffffff03c0d40100000000001976a91424cba659aad4563de9199f3fe273bac07f170eb088ac409c0000000000001976a91418dc74eb38930493ce81b8f1d3fd0f15e43e96b288ac30750000000000001976a9142030bc3fec2b3783acd9e83f6e24d57568be69a988ac00000000"

{- TxID: 03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582
 - inputs: acc1 (index 0 = 120000)
 - Payments sent to:
 - 13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf : 110000 (outside)
 -}

txD :: String
txD = "010000000150b18a410fdc69cf463134a357c6ef0c5b0651723dda6164c300ffe356db5522000000006b483045022100f9a43bc03aa44ea2e97873d73f522680a7967f71ad9406de380aafd8f1afc1260220790f82a126d2a5a5404ea2632c99e90e55484e1d16dba1842884bc740add3f23012103a104bc20b43f7f10f89f0519b12bd828dfb7c7969e4c833eadfc6badda334bc0ffffffff01b0ad0100000000001976a9141f69921a4f95254ee2aaa181381439bbc8b2645788ac00000000"

testOrphan :: ( PersistStore m, PersistUnique m, PersistQuery m
              , PersistMonadBackend m ~ SqlBackend
              ) 
           => EitherT String m ()
testOrphan = do 

    -- import transaction D
    cmdImportTx (decode' $ fromJust $ hexToBS txD) >>= 
        liftIO . assertEqual "import txD"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                             ]
                         , "Value"      .= (0 :: Int)
                         , "Orphan"     .= True
                         ]
                ]
            )

    -- import transaction D a second time. Operation should be idempotent
    cmdImportTx (decode' $ fromJust $ hexToBS txD) >>= 
        liftIO . assertEqual "import txD 2"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                             ]
                         , "Value"      .= (0 :: Int)
                         , "Orphan"     .= True
                         ]
                ]
            )

    (Entity ai1 _) <- dbGetAcc "acc1"
    (Entity ai2 _) <- dbGetAcc "acc2"

    let f (Entity _ c) = ( dbCoinTxid c, dbCoinPos c
                         , dbCoinValue c, dbCoinScript c
                         , dbCoinRdmScript c, dbCoinAddress c
                         , dbCoinStatus c, dbCoinOrphan c
                         )
        g (Entity _ t) = ( dbTxTxid t, dbTxRecipients t
                         , dbTxValue t, dbTxOrphan t, dbTxPartial t
                         )

    ((map f) <$> selectList [DbCoinAccount ==. ai1] [Asc DbCoinCreated]) >>= 
        liftIO . assertEqual "Check import txD coins"
            [ ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , 0, 0, "", Nothing 
              , "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
              , Spent "03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582"
              , True
              )
            ]

    ((map g) <$> selectList [DbTxAccount ==. ai1] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Check import txD tx"
            [ ( "03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582"
              , ["13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"]
              , 0, True, False
              )
            ]

    cmdCoins "acc1" >>= liftIO . assertEqual "Check empty coins txD" 
        (toJSON ([] :: [DbCoinGeneric b]))

    cmdListTx "acc1" >>= liftIO . assertEqual "Check listTx txD"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                         ]
                     , "Value"      .= (0 :: Int)
                     , "Orphan"     .= True
                     ]
            ]
        )

    cmdBalance "acc1" >>= liftIO . assertEqual "Check 0 balance txD" 
        (object ["Balance" .= (0 :: Int)])

    -- import transaction C
    cmdImportTx (decode' $ fromJust $ hexToBS txC) >>= 
        liftIO . assertEqual "import txC"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             ]
                         , "Value"      .= (120000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                             ]
                         , "Value"      .= (0 :: Int)
                         , "Orphan"     .= True
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                             ]
                         , "Value"      .= (-120000 :: Int)
                         ]
                ]
            )

    -- import transaction C again (operation should be idempotent)
    cmdImportTx (decode' $ fromJust $ hexToBS txC) >>= 
        liftIO . assertEqual "import txC 2"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             ]
                         , "Value"      .= (120000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                             ]
                         , "Value"      .= (0 :: Int)
                         , "Orphan"     .= True
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                             ]
                         , "Value"      .= (-120000 :: Int)
                         ]
                ]
            )

    -- The previous orphaned coin should be un-orphaned now
    ((map f) <$> selectList [DbCoinAccount ==. ai1] [Asc DbCoinCreated]) >>= 
        liftIO . assertEqual "Check import txC coins 2"
            [ ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , 0, 120000
              , "76a91424cba659aad4563de9199f3fe273bac07f170eb088ac", Nothing 
              , "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
              , Spent "03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582"
              , False
              )
            ]

    -- The creation time of the transactions should reflect their dependencies
    ((map g) <$> selectList [DbTxAccount ==. ai1] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Check import txC tx"
            [ ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , ["14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"]
              , 120000, False, False
              )
            , ( "03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582"
              , ["13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"]
              , -120000, False, False
              )
            ]

    -- Check coins of account 2
    ((map f) <$> selectList [DbCoinAccount ==. ai2] [Asc DbCoinCreated]) >>= 
        liftIO . assertEqual "Check import txC coins 3"
            [ ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , 1, 0
              , "", Nothing 
              , "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
              , Spent "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150" 
              , True
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , 2, 30000
              , "76a9142030bc3fec2b3783acd9e83f6e24d57568be69a988ac", Nothing 
              , "13wD1L9PvEgBytP5X6ykiuhB8gRP58CB5J"
              , Unspent , False
              )
            ]

    -- Check transactions of account 2
    ((map g) <$> selectList [DbTxAccount ==. ai2] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Check import txC tx 2"
            [ ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , [ "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                , "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                ]
              , 0, True, False
              )
            ]

    -- list cmdCoins of acc 1 (should be empty)
    cmdCoins "acc1" >>= liftIO . assertEqual "Check cmdCoins txC 1" 
        (toJSON ([] :: [DbCoinGeneric b]))

    -- list cmdCoins of acc 2
    cmdCoins "acc2" >>= liftIO . assertEqual "Check cmdCoins txC 2" 
        (toJSON 
            [ object [ "TxID"    .= T.pack "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
                     , "Index"   .= (2 :: Int)
                     , "Value"   .= (30000 :: Int)
                     , "Script"  .= T.pack "76a9142030bc3fec2b3783acd9e83f6e24d57568be69a988ac"
                     , "Address" .= T.pack "13wD1L9PvEgBytP5X6ykiuhB8gRP58CB5J"
                     ] 
            ]
        )

    -- list cmdListTx of acc1
    cmdListTx "acc1" >>= liftIO . assertEqual "Check listTx txC 1"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                         ]
                     , "Value"      .= (120000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                         ]
                     , "Value"      .= (-120000 :: Int)
                     ]
            ]
        )

    -- list cmdListTx of acc2
    cmdListTx "acc2" >>= liftIO . assertEqual "Check listTx txC 2"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                         , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                         ]
                     , "Value"      .= (0 :: Int)
                     , "Orphan"     .= True
                     ]
            ]
        )

    -- Check balance of acc1
    cmdBalance "acc1" >>= liftIO . assertEqual "Check balance txC 1" 
        (object ["Balance" .= (0 :: Int)])

    -- Balance of acc2 is 30000 but pending orphaned coins
    cmdBalance "acc2" >>= liftIO . assertEqual "Check balance txC 2" 
        (object ["Balance" .= (30000 :: Int)])

    -- Importing txB
    cmdImportTx (decode' $ fromJust $ hexToBS txB) >>= 
        liftIO . assertEqual "import txB 1"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
                             , T.pack "1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86"
                             ]
                         , "Value"      .= (0 :: Int)
                         , "Orphan"     .= True
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M" ]
                         , "Value"      .= (200000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             ]
                         , "Value"      .= (120000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                             ]
                         , "Value"      .= (-170000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                             ]
                         , "Value"      .= (-120000 :: Int)
                         ]
                ]
            )

    -- Importing txB again. Import is idempotent so this should work fine
    cmdImportTx (decode' $ fromJust $ hexToBS txB) >>= 
        liftIO . assertEqual "import txB 1"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
                             , T.pack "1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86"
                             ]
                         , "Value"      .= (0 :: Int)
                         , "Orphan"     .= True
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M" ]
                         , "Value"      .= (200000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             ]
                         , "Value"      .= (120000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                             ]
                         , "Value"      .= (-170000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                             ]
                         , "Value"      .= (-120000 :: Int)
                         ]
                ]
            )

    -- List coins of account 1 after importing txB
    ((map f) <$> selectList [DbCoinAccount ==. ai1] [Asc DbCoinCreated]) >>= 
        liftIO . assertEqual "Check import txB coins"
            [ ( "23c5dcac6ef51d36ca63cf7f3dc30163939bb208eb8e12b92183ccc1333c20bd"
              , 1, 0
              , "", Nothing 
              , "1DKe1dvRznGqmBFsHY7MmvJy3DtcfBDZbw"
              , Spent "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , True
              )
            , ( "23c5dcac6ef51d36ca63cf7f3dc30163939bb208eb8e12b92183ccc1333c20bd"
              , 2, 0
              , "", Nothing 
              , "17yJQpBHpWyVHNshgGpCK876Nb8qqvp3rG"
              , Spent "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , True
              )
            , ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , 0, 100000
              , "76a914243d03889d49470ee721d44596fd146440e1167c88ac", Nothing 
              , "14JcRDidCbYFBwWjP9PGJL1MRKCzUWCmaS"
              , Unspent
              , False
              )
            , ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , 3, 40000
              , "76a914740eb168ae243882a73f5467b9024431443ef12988ac", Nothing 
              , "1Baez98Lapiu7mQLfXuUCjBreEAwFrWNd2"
              , Unspent
              , False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , 0, 120000
              , "76a91424cba659aad4563de9199f3fe273bac07f170eb088ac", Nothing 
              , "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
              , Spent "03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582"
              , False
              )
            ]

    -- List of transactions for account 1
    ((map g) <$> selectList [DbTxAccount ==. ai1] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Check transactions import txB"
            [ ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , [ "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
                , "1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86"
                ]
              , 0, True, False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , ["14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"]
              , 120000, False, False
              )
            , ( "03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582"
              , ["13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"]
              , -120000, False, False
              )
            ]

    -- List coins of account 2. The first coin is not orphaned anymore
    ((map f) <$> selectList [DbCoinAccount ==. ai2] [Asc DbCoinCreated]) >>= 
        liftIO . assertEqual "Check coins txB 2"
            [ ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , 1, 200000
              , "76a9143f53fba59a1c17f17cf3c4b5cfcf15fa0087f1c188ac", Nothing 
              , "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
              , Spent "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150" 
              , False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , 2, 30000
              , "76a9142030bc3fec2b3783acd9e83f6e24d57568be69a988ac", Nothing 
              , "13wD1L9PvEgBytP5X6ykiuhB8gRP58CB5J"
              , Unspent , False
              )
            ]

    -- Check transactions of account 2
    ((map g) <$> selectList [DbTxAccount ==. ai2] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Check transactions import txB 2"
            [ ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , [ "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M" ]
              , 200000, False, False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , [ "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                , "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                ]
              , -170000, False, False
              )
            ]

    -- list cmdCoins of acc 1
    cmdCoins "acc1" >>= liftIO . assertEqual "Check cmdCoins txB 1" 
        (toJSON 
            [ object [ "TxID"    .= T.pack "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
                     , "Index"   .= (0 :: Int)
                     , "Value"   .= (100000 :: Int)
                     , "Script"  .= T.pack "76a914243d03889d49470ee721d44596fd146440e1167c88ac"
                     , "Address" .= T.pack "14JcRDidCbYFBwWjP9PGJL1MRKCzUWCmaS"
                     ] 
            , object [ "TxID"    .= T.pack "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
                     , "Index"   .= (3 :: Int)
                     , "Value"   .= (40000 :: Int)
                     , "Script"  .= T.pack "76a914740eb168ae243882a73f5467b9024431443ef12988ac"
                     , "Address" .= T.pack "1Baez98Lapiu7mQLfXuUCjBreEAwFrWNd2"
                     ] 
            ]
        )

    -- list cmdCoins of acc 2
    cmdCoins "acc2" >>= liftIO . assertEqual "Check cmdCoins txB 2" 
        (toJSON 
            [ object [ "TxID"    .= T.pack "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
                     , "Index"   .= (2 :: Int)
                     , "Value"   .= (30000 :: Int)
                     , "Script"  .= T.pack "76a9142030bc3fec2b3783acd9e83f6e24d57568be69a988ac"
                     , "Address" .= T.pack "13wD1L9PvEgBytP5X6ykiuhB8gRP58CB5J"
                     ] 
            ]
        )

    -- list cmdListTx of acc1
    cmdListTx "acc1" >>= liftIO . assertEqual "Check listTx txB 1"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
                         , T.pack "1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86"
                         ]
                     , "Value"      .= (0 :: Int)
                     , "Orphan"     .= True
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                         ]
                     , "Value"      .= (120000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                         ]
                     , "Value"      .= (-120000 :: Int)
                     ]
            ]
        )

    -- list cmdListTx of acc2
    cmdListTx "acc2" >>= liftIO . assertEqual "Check listTx txB 2"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M" ]
                     , "Value"      .= (200000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                         , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                         ]
                     , "Value"      .= (-170000 :: Int)
                     ]
            ]
        )

    -- Check balance of acc1
    cmdBalance "acc1" >>= liftIO . assertEqual "Check balance txB 1" 
        (object ["Balance" .= (140000 :: Int)])

    -- Balance of acc2 
    cmdBalance "acc2" >>= liftIO . assertEqual "Check balance txB 2" 
        (object ["Balance" .= (30000 :: Int)])

    -- Importing txA (Partial)
    cmdImportTx (decode' $ fromJust $ hexToBS txA) >>= 
        liftIO . assertEqual "import txA 1"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "1ChqhDvLVx5bjRHbdUweCsd4mgwD4fvdGL"
                             , T.pack "1DKe1dvRznGqmBFsHY7MmvJy3DtcfBDZbw"
                             , T.pack "17yJQpBHpWyVHNshgGpCK876Nb8qqvp3rG"
                             ]
                         , "Value"      .= (600000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
                             , T.pack "1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86"
                             ]
                         , "Value"      .= (-360000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M" ]
                         , "Value"      .= (200000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             ]
                         , "Value"      .= (120000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                             ]
                         , "Value"      .= (-170000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf" ]
                         , "Value"      .= (-120000 :: Int)
                         ]
                ]
            )

    -- Importing txA a second time
    cmdImportTx (decode' $ fromJust $ hexToBS txA) >>= 
        liftIO . assertEqual "import txA 1"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "1ChqhDvLVx5bjRHbdUweCsd4mgwD4fvdGL"
                             , T.pack "1DKe1dvRznGqmBFsHY7MmvJy3DtcfBDZbw"
                             , T.pack "17yJQpBHpWyVHNshgGpCK876Nb8qqvp3rG"
                             ]
                         , "Value"      .= (600000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
                             , T.pack "1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86"
                             ]
                         , "Value"      .= (-360000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M" ]
                         , "Value"      .= (200000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             ]
                         , "Value"      .= (120000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                             ]
                         , "Value"      .= (-170000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf" ]
                         , "Value"      .= (-120000 :: Int)
                         ]
                ]
            )

    -- List coins of account 1 after importing txA
    ((map f) <$> selectList [DbCoinAccount ==. ai1] [Asc DbCoinCreated]) >>= 
        liftIO . assertEqual "Check import txB coins"
            [ ( "23c5dcac6ef51d36ca63cf7f3dc30163939bb208eb8e12b92183ccc1333c20bd"
              , 0, 100000
              , "76a9148062ab5c3fdf5f8f0d41fccacbb3ea8058b911ae88ac", Nothing 
              , "1ChqhDvLVx5bjRHbdUweCsd4mgwD4fvdGL"
              , Unspent, False
              )
            , ( "23c5dcac6ef51d36ca63cf7f3dc30163939bb208eb8e12b92183ccc1333c20bd"
              , 1, 200000
              , "76a9148727e4552058a555d0ce269d8cf8c850785666f688ac", Nothing 
              , "1DKe1dvRznGqmBFsHY7MmvJy3DtcfBDZbw"
              , Spent "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , False
              )
            , ( "23c5dcac6ef51d36ca63cf7f3dc30163939bb208eb8e12b92183ccc1333c20bd"
              , 2, 300000
              , "76a9144c769509bb3e22c2275cd025fcb55ebc5dc1e39f88ac", Nothing 
              , "17yJQpBHpWyVHNshgGpCK876Nb8qqvp3rG"
              , Spent "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , False
              )
            , ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , 0, 100000
              , "76a914243d03889d49470ee721d44596fd146440e1167c88ac", Nothing 
              , "14JcRDidCbYFBwWjP9PGJL1MRKCzUWCmaS"
              , Unspent, False
              )
            , ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , 3, 40000
              , "76a914740eb168ae243882a73f5467b9024431443ef12988ac", Nothing 
              , "1Baez98Lapiu7mQLfXuUCjBreEAwFrWNd2"
              , Unspent, False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , 0, 120000
              , "76a91424cba659aad4563de9199f3fe273bac07f170eb088ac", Nothing 
              , "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
              , Spent "03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582"
              , False
              )
            ]

    -- List of transactions for account 1
    ((map g) <$> selectList [DbTxAccount ==. ai1] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Check transactions import txA"
            [ ( "23c5dcac6ef51d36ca63cf7f3dc30163939bb208eb8e12b92183ccc1333c20bd"
              , [ "1ChqhDvLVx5bjRHbdUweCsd4mgwD4fvdGL"
                , "1DKe1dvRznGqmBFsHY7MmvJy3DtcfBDZbw"
                , "17yJQpBHpWyVHNshgGpCK876Nb8qqvp3rG"
                ]
              , 600000, False, False
              )
            , ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , [ "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
                , "1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86"
                ]
              , -360000, False, False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , ["14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"]
              , 120000, False, False
              )
            , ( "03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582"
              , ["13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"]
              , -120000, False, False
              )
            ]

    -- List coins of account 2
    ((map f) <$> selectList [DbCoinAccount ==. ai2] [Asc DbCoinCreated]) >>= 
        liftIO . assertEqual "Check coins txA 2"
            [ ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , 1, 200000
              , "76a9143f53fba59a1c17f17cf3c4b5cfcf15fa0087f1c188ac", Nothing 
              , "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
              , Spent "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150" 
              , False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , 2, 30000
              , "76a9142030bc3fec2b3783acd9e83f6e24d57568be69a988ac", Nothing 
              , "13wD1L9PvEgBytP5X6ykiuhB8gRP58CB5J"
              , Unspent , False
              )
            ]

    -- Check transactions of account 2
    ((map g) <$> selectList [DbTxAccount ==. ai2] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Check transactions import txA 2"
            [ ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , [ "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M" ]
              , 200000, False, False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , [ "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                , "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                ]
              , -170000, False, False
              )
            ]

    -- list cmdCoins of acc 1
    cmdCoins "acc1" >>= liftIO . assertEqual "Check cmdCoins txA 1" 
        (toJSON 
            [ object [ "TxID"    .= T.pack "23c5dcac6ef51d36ca63cf7f3dc30163939bb208eb8e12b92183ccc1333c20bd"
                     , "Index"   .= (0 :: Int)
                     , "Value"   .= (100000 :: Int)
                     , "Script"  .= T.pack "76a9148062ab5c3fdf5f8f0d41fccacbb3ea8058b911ae88ac"
                     , "Address" .= T.pack "1ChqhDvLVx5bjRHbdUweCsd4mgwD4fvdGL"
                     ] 
            , object [ "TxID"    .= T.pack "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
                     , "Index"   .= (0 :: Int)
                     , "Value"   .= (100000 :: Int)
                     , "Script"  .= T.pack "76a914243d03889d49470ee721d44596fd146440e1167c88ac"
                     , "Address" .= T.pack "14JcRDidCbYFBwWjP9PGJL1MRKCzUWCmaS"
                     ] 
            , object [ "TxID"    .= T.pack "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
                     , "Index"   .= (3 :: Int)
                     , "Value"   .= (40000 :: Int)
                     , "Script"  .= T.pack "76a914740eb168ae243882a73f5467b9024431443ef12988ac"
                     , "Address" .= T.pack "1Baez98Lapiu7mQLfXuUCjBreEAwFrWNd2"
                     ] 
            ]
        )

    -- list cmdCoins of acc 2
    cmdCoins "acc2" >>= liftIO . assertEqual "Check cmdCoins txA 2" 
        (toJSON 
            [ object [ "TxID"    .= T.pack "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
                     , "Index"   .= (2 :: Int)
                     , "Value"   .= (30000 :: Int)
                     , "Script"  .= T.pack "76a9142030bc3fec2b3783acd9e83f6e24d57568be69a988ac"
                     , "Address" .= T.pack "13wD1L9PvEgBytP5X6ykiuhB8gRP58CB5J"
                     ] 
            ]
        )

    -- list cmdListTx of acc1
    cmdListTx "acc1" >>= liftIO . assertEqual "Check listTx txA 1"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "1ChqhDvLVx5bjRHbdUweCsd4mgwD4fvdGL"
                         , T.pack "1DKe1dvRznGqmBFsHY7MmvJy3DtcfBDZbw"
                         , T.pack "17yJQpBHpWyVHNshgGpCK876Nb8qqvp3rG"
                         ]
                     , "Value"      .= (600000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
                         , T.pack "1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86"
                         ]
                     , "Value"      .= (-360000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                         ]
                     , "Value"      .= (120000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                         ]
                     , "Value"      .= (-120000 :: Int)
                     ]
            ]
        )

    -- list cmdListTx of acc2
    cmdListTx "acc2" >>= liftIO . assertEqual "Check listTx txA 2"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M" ]
                     , "Value"      .= (200000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                         , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                         ]
                     , "Value"      .= (-170000 :: Int)
                     ]
            ]
        )

    -- Check balance of acc1
    cmdBalance "acc1" >>= liftIO . assertEqual "Check balance txA 1" 
        (object ["Balance" .= (240000 :: Int)])

    -- Balance of acc2 
    cmdBalance "acc2" >>= liftIO . assertEqual "Check balance txA 2" 
        (object ["Balance" .= (30000 :: Int)])

    -- Re-Importing a transaction in the middle of the chain
    cmdImportTx (decode' $ fromJust $ hexToBS txC) >>= 
        liftIO . assertEqual "import txC BIS"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             ]
                         , "Value"      .= (120000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                             , T.pack "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                             ]
                         , "Value"      .= (-170000 :: Int)
                         ]
                , object [ "Recipients" .= toJSON
                             [ T.pack "13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"
                             ]
                         , "Value"      .= (-120000 :: Int)
                         ]
                ]
            )

    -- Verify that the transaction orders haven't changed
    ((map g) <$> selectList [DbTxAccount ==. ai1] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Last order verification"
            [ ( "23c5dcac6ef51d36ca63cf7f3dc30163939bb208eb8e12b92183ccc1333c20bd"
              , [ "1ChqhDvLVx5bjRHbdUweCsd4mgwD4fvdGL"
                , "1DKe1dvRznGqmBFsHY7MmvJy3DtcfBDZbw"
                , "17yJQpBHpWyVHNshgGpCK876Nb8qqvp3rG"
                ]
              , 600000, False, False
              )
            , ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , [ "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M"
                , "1FLRUj4iGRZHpr9WJq3RG64cL2vEbccQ86"
                ]
              , -360000, False, False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , ["14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"]
              , 120000, False, False
              )
            , ( "03e0ce2206a300bfc718afd25e1d34bc3a0b61e570913c4ab94884219b031582"
              , ["13s6R8TRWTk5DZaSQ2pKn3hfdugvEZEdZf"]
              , -120000, False, False
              )
            ]

    -- Verify that the transaction order haven't changed
    ((map g) <$> selectList [DbTxAccount ==. ai2] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Last order verification 2"
            [ ( "53fe1114579ef53affe2339d3cd5010b054515556bc9749351e96b24f9cba3d0"
              , [ "16mrBKvB9DV5YAYw7a8kYDvqwh1tJGMR5M" ]
              , 200000, False, False
              )
            , ( "2255db56e3ff00c36461da3d7251065b0cefc657a3343146cf69dc0f418ab150"
              , [ "14MZHk4dkM3ZM7bBcET4ELuyozXqCCsQpb"
                , "13GTKCtWbpRpPGca3uhTjwZWiQcqAMPh6n"
                ]
              , -170000, False, False
              )
            ]


testSend :: ( PersistStore m, PersistUnique m, PersistQuery m
            , PersistMonadBackend m ~ SqlBackend
            ) 
         => EitherT String m ()
testSend = do 

    -- Send some money to an outside address
    cmdSendMany "acc1" 
        [ ("19w9Btacp9tYgbhWE9d8yEdhR15XcjE9XZ", 20000) -- outside
        , ("1D8KWhk1x2EGqEUXi1GMJmqmRRWebH8XmT", 30000) -- outside
        ] 10000 >>= liftIO . assertEqual "send normal tx"
            ( object [ "Tx" .= T.pack "0100000001bd203c33c1cc8321b9128eeb08b29b936301c33d7fcf63ca361df56eacdcc523000000006b483045022100b45842dae5f62c6564c9133891bab410ec8b9129580bf98762fc66ae6be45b6c02207cf90bdc82e2d538a46e3580a7b639737c2d334cdd74df65ee24770d2ac8fb940121020ab91e1cdcaf0d13ca13f1b0b975184882a90ee369f4ac6eab00caacca36b423ffffffff03204e0000000000001976a91461fe4d90fbb250c29e24aaff95f14218c0d39f3388ac30750000000000001976a9148503dfd0281b679af0770d5894cdf0402047befa88ac409c0000000000001976a9146d1523de2ac60a29e60f6584956032054302e73a88ac00000000"
                     , "Complete" .= True
                     ]
            )

    -- Same as before but set the amount such that the change would
    -- result in dust. The dust should be donated as tx fee
    cmdSendMany "acc1" 
        [ ("19w9Btacp9tYgbhWE9d8yEdhR15XcjE9XZ", 44000) -- outside
        , ("1D8KWhk1x2EGqEUXi1GMJmqmRRWebH8XmT", 44000) -- outside
        ] 10000 >>= liftIO . assertEqual "send normal tx no change"
            ( object [ "Tx" .= T.pack "0100000001bd203c33c1cc8321b9128eeb08b29b936301c33d7fcf63ca361df56eacdcc523000000006a47304402207a68a43941c387787a611b7775e487dced559f7331f00aa143d87bf4c6dc447802203d56aa3c9e3b209da4396e771c734d68b6b99c52528c8255dc552fe42a7d67be0121020ab91e1cdcaf0d13ca13f1b0b975184882a90ee369f4ac6eab00caacca36b423ffffffff02e0ab0000000000001976a91461fe4d90fbb250c29e24aaff95f14218c0d39f3388ace0ab0000000000001976a9148503dfd0281b679af0770d5894cdf0402047befa88ac00000000"
                     , "Complete" .= True
                     ]
            )

    let emptyTx = "0100000001bd203c33c1cc8321b9128eeb08b29b936301c33d7fcf63ca361df56eacdcc5230000000000ffffffff02e0ab0000000000001976a91461fe4d90fbb250c29e24aaff95f14218c0d39f3388ace0ab0000000000001976a9148503dfd0281b679af0770d5894cdf0402047befa88ac00000000"

    -- Sign an empty shell transaction with cmdSignTx
    cmdSignTx "acc1" (decode' $ fromJust $ hexToBS emptyTx) (SigAll False) >>= 
        liftIO . assertEqual "sign empty transaction"
            ( object [ "Tx"       .= T.pack "0100000001bd203c33c1cc8321b9128eeb08b29b936301c33d7fcf63ca361df56eacdcc523000000006a47304402207a68a43941c387787a611b7775e487dced559f7331f00aa143d87bf4c6dc447802203d56aa3c9e3b209da4396e771c734d68b6b99c52528c8255dc552fe42a7d67be0121020ab91e1cdcaf0d13ca13f1b0b975184882a90ee369f4ac6eab00caacca36b423ffffffff02e0ab0000000000001976a91461fe4d90fbb250c29e24aaff95f14218c0d39f3388ace0ab0000000000001976a9148503dfd0281b679af0770d5894cdf0402047befa88ac00000000"
                     , "Complete" .= True
                     ]
            )

    -- Sign an empty shell transaction with cmdSignTx. Should fail as
    -- acc2 does not have any of the inputs
    cmdSignTx "acc2" (decode' $ fromJust $ hexToBS emptyTx) (SigAll False) >>= 
        liftIO . assertEqual "sign empty transaction 2"
            ( object [ "Tx"       .= T.pack emptyTx
                     , "Complete" .= False
                     ]
            )

    -- Sending more coins than you have should fail
    (runEitherT $ cmdSendMany "acc1" 
        [ ("15WAh7HRms3HDFLEAtMuBM4aUcwvN7B2QY", 300000) -- outside
        , ("1CzjVJfn1RmNes4ZEKGRA8VJcpCB1xfNvp", 110000) -- outside
        ] 10000) >>= liftIO . assertEqual "Send too many coins"
            (Left "chooseCoins: No solution found")

    -- Spending coins from a multisignature account
    cmdSendMany "ms1" 
        [ ("15WAh7HRms3HDFLEAtMuBM4aUcwvN7B2QY", 300000) -- outside
        , ("1CzjVJfn1RmNes4ZEKGRA8VJcpCB1xfNvp", 110000) -- outside
        ] 10000 >>= liftIO . assertEqual "Send coins from multisig coins"
            ( object [ "Tx" .= T.pack "0100000003711707c27ce6fad18ddf3542de57bea6dbf211a18723717ee3844e9aaec5629000000000b50047304402206fa37ea2fcc6467c788b321be6c8db6b52c1c328dfe3397c1d0c3f06b13ef1bc02203afdcca94843391019cf0a38331a85f7ae5b24df28c397adb4ebecbd5390db2901004c695221026e294fcecdcbae12a0aba1685db35c54ddfc1375d48f96ff1b8805a4bb57bfc921028bc8d8377f44de8ac8beff0dc9ccefde4cd5dded7b8cd8babe02c7147a90ba6c21039cf5d06e79871043c420fabc652f8082e702e0094f91ec14c020e9fcf48fa4d853aeffffffff85e7fcc7399ef68c3277ab4be6aecfa7f77781a99d3a8e0038f03846fb269f3104000000b600483045022100caeda000f0a7144721439020edee8c9f20f41afc63288ea732b2483f1f3b77a202207d727f06e2a5661eff977a7f29bf563a9e3fc11bc3e191a246a722cfc9ab9a6601004c695221026e294fcecdcbae12a0aba1685db35c54ddfc1375d48f96ff1b8805a4bb57bfc921028bc8d8377f44de8ac8beff0dc9ccefde4cd5dded7b8cd8babe02c7147a90ba6c21039cf5d06e79871043c420fabc652f8082e702e0094f91ec14c020e9fcf48fa4d853aeffffffff96a9342b5d88583a607e8cc43a4fd844a9dfc3ef9f72982db4dac3b708f356a104000000b500473044022070bdccc43981a4a341f27b4e8ed146301ce82c1c571f483b7d457f20bc754b4402201deefab82e52a0235c336fd24e7ccf1ec47b5751f4b8a472b0a23543d9b7e42401004c695221026e294fcecdcbae12a0aba1685db35c54ddfc1375d48f96ff1b8805a4bb57bfc921028bc8d8377f44de8ac8beff0dc9ccefde4cd5dded7b8cd8babe02c7147a90ba6c21039cf5d06e79871043c420fabc652f8082e702e0094f91ec14c020e9fcf48fa4d853aeffffffff02e0930400000000001976a9143164a7f65ce9d354a8ded150547a9523df056b3588acb0ad0100000000001976a91483948f86afa40df4836e88f402aff1e540469ba588ac00000000"
                     , "Complete" .= False
                     ]
            )

    _ <- cmdNewMS "signms" 2 3 []
    
    _ <- cmdAddKeys "signms" [fromJust $ xPubImport "xpub69QmF5x2m5duxo856Dg622vDjsxtDCwMAaLyhVjBZDDTaKbenBfMByNJVMYKAVTEpGPDePdgjDpDyPvBPx4WpFV8zmNEa6Cx7Lk4Bn9PDcE"]

    _ <- cmdAddKeys "signms" [fromJust $ xPubImport "xpub69QmF5x2m5dv1r2xNBLTq6HGKjFDyE4iAhxhdL4FgVR8vQprruLcauxJNdASANJaZc65bmoD1snK4db9DDYAuEBo3ANZik9SHnTAKQZLDt1"]

--    cmdNewMS "test2" 2 3 []
--    cmdNewMS "test3" 2 3 []
--
--    deleteBy $ UniqueAccName "signms"
--    deleteBy $ UniqueAccName "test2"
--
--    cmdAddKeys "test3" [fromJust $ xPubImport "xpub69QmF5x2m5duvyfWu3DjU9r9CkTKp5poGCnVLBmRBgJaye7LQ9yPs55z7zPZDpp6X4BHru9EpF8hqQGNa2ipEmBx9rYq6LdvNht6M2qqxUm"]
--
--    cmdAddKeys "test3" [fromJust $ xPubImport "xpub69QmF5x2m5duxo856Dg622vDjsxtDCwMAaLyhVjBZDDTaKbenBfMByNJVMYKAVTEpGPDePdgjDpDyPvBPx4WpFV8zmNEa6Cx7Lk4Bn9PDcE"]

{- TxID: 62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589
 - Input: 03-01
 - Outputs:
 - 3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E : 100000
 - 3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW : 200000
 - 3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR : 150000
 - 3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp : 180000 
 -}

    let fundingTx = decode' $ fromJust $ hexToBS "01000000010000000000000000000000000000000000000000000000000000000000000001030000006a47304402206992bec0f95102a9994dd77e0b910af0b19b0b94d94423c68bb49ed57890238402203b15cbb6e1edcb686891138b057acac4cb67247f6bf693f38bd35d8c6605bca201210290a14bce9d363667574a29da1b2e38d106968969f449588713bb271e28a9a4a0ffffffff04a08601000000000017a91491b00b8d4d4b8909d5d17fe8da3b09fbd64e003c87400d03000000000017a91488fb2eb63c1f992d801f538340180527510464c787f04902000000000017a9148c0ad01947abab4985837a24be0d2141dcba06398720bf02000000000017a91460c1eb9034130684ece4594384e984325d1280ad8700000000"

{- TxID: 74ea8680000dd5e4f0122e47c73de7b0b02aae478a03930c5f547f67ed3dabcb
 - Inputs: 1,2,3
 - Outputs: 
 - 13LjjLQGGiTL8AYMbYqBmQVyAMyQnjPZK3 : 300000
 - 1MK3xFQSekQPuety1oaVTmvLRusFYsTq3d : 140000
 - 3CDgiQ2TnKvy1AovxwFy2jsDqURN8bq856 :  80000 (Change)
 -}
    let partialTx = "01000000038935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76202000000b6004830450221009d876833374da1714aa42945b73fe2af9ee37fdf32b4db9dd10297c0a9a18257022065618d04ead4ba5e4201bf15f149f1429e83173d42e31246d3164f2072e6605901004c69522102779d361a5d534dfca9d480eb60a1b14741a98d29f5c984fc1afd68a8c50981232102f579364c0d0971ec9ae52f2fc870204bce00438be1b6fa695d27c9d01cfb0956210383787221b68f601aa4695c27e7eebb0d15de2ed7ef7b9981fba8cad71ae2d84253aeffffffff8935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76203000000b600483045022100f8f9274fcf04200031578f5bfa0ecd108f5c945d7efef5f4fe519943d945594502200941f22088458750894005366a74857b72fb59197405bd2298947d96456d165b01004c6952210285bd8161363c6e2d2c075e08ed8a956c4706ccd77497a31327bf92b2208c3587210286e3177a8ca61d2d9426b4230735631e8552cc4d6e87e1277960461b0d26aac42103e2e138589e064f347238c2ca46c1d7deb8dd9472d065d7c5cb0f91aa5cc210a953aeffffffff8935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76201000000b50047304402200469180f9e94bf6d1d03ce07411bfd107b78f2fb1b1a862fc39dfeece417d14b02206696f963f97d3a6aaddc295c8eaf1846fef07f44c46d3aa97f09a4c0b72476c101004c695221023206a385544defd500a54d3d3fd8982d35fa7f877fa721beb59e440186183e8a210352b7c1f82593abebcb4ad0bbf28a4317b49efc1cc3e647453c09c6375122e8f621035c9ca1f7825d2cf025f42e636f57f193dbaae5c18b08dca10bf996ddb58eb8e853aeffffffff03e0930400000000001976a91419abd2efb4cd44b132ffd6206aa35e60f9d3e4b988ace0220200000000001976a914decc77b87d2199a51532034ad63f59cae6e6c4f588ac803801000000000017a914737e1e10bbf4290c82681745b5a54449ca83d1848700000000"

-- ID: a7274a15719099c5de37741bfd70efa15bb22a9de5507d966ccdf528a4f8f4c3

    let finalTx = "01000000038935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76202000000fdfd00004830450221009d876833374da1714aa42945b73fe2af9ee37fdf32b4db9dd10297c0a9a18257022065618d04ead4ba5e4201bf15f149f1429e83173d42e31246d3164f2072e6605901473044022065316243de4edd6e1741580a11489a5445b4fc35efcb13aa6189f1a524f6745a022003fdf5273c90ac7d906cba33f42661dcac45e80aab9aecd4fcd5ed5e9595c239014c69522102779d361a5d534dfca9d480eb60a1b14741a98d29f5c984fc1afd68a8c50981232102f579364c0d0971ec9ae52f2fc870204bce00438be1b6fa695d27c9d01cfb0956210383787221b68f601aa4695c27e7eebb0d15de2ed7ef7b9981fba8cad71ae2d84253aeffffffff8935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76203000000fdfd000047304402205c1bd8303745cbcc3f3412ee6f19090519ef2b72a03c799325ebd2188783bc670220298b8b13cf726beccf0909c83016a22c8429df4a2982f7ea54b24f40dd6a27ac01483045022100f8f9274fcf04200031578f5bfa0ecd108f5c945d7efef5f4fe519943d945594502200941f22088458750894005366a74857b72fb59197405bd2298947d96456d165b014c6952210285bd8161363c6e2d2c075e08ed8a956c4706ccd77497a31327bf92b2208c3587210286e3177a8ca61d2d9426b4230735631e8552cc4d6e87e1277960461b0d26aac42103e2e138589e064f347238c2ca46c1d7deb8dd9472d065d7c5cb0f91aa5cc210a953aeffffffff8935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76201000000fdfd000047304402200469180f9e94bf6d1d03ce07411bfd107b78f2fb1b1a862fc39dfeece417d14b02206696f963f97d3a6aaddc295c8eaf1846fef07f44c46d3aa97f09a4c0b72476c101483045022100e865ba910c96823cc9ddf6b65d62f6d107ca5589a866f3814d048ada70a01b3102201025101604ccf2f639a7f7176517665656b04c9a531d3e542eb495095148b802014c695221023206a385544defd500a54d3d3fd8982d35fa7f877fa721beb59e440186183e8a210352b7c1f82593abebcb4ad0bbf28a4317b49efc1cc3e647453c09c6375122e8f621035c9ca1f7825d2cf025f42e636f57f193dbaae5c18b08dca10bf996ddb58eb8e853aeffffffff03e0930400000000001976a91419abd2efb4cd44b132ffd6206aa35e60f9d3e4b988ace0220200000000001976a914decc77b87d2199a51532034ad63f59cae6e6c4f588ac803801000000000017a914737e1e10bbf4290c82681745b5a54449ca83d1848700000000"

    liftIO $ assertBool "Partial transaction not complete" $ 
        not $ isTxComplete (decode' $ fromJust $ hexToBS partialTx)

    liftIO $ assertBool "Final transaction complete" $ 
        isTxComplete (decode' $ fromJust $ hexToBS finalTx)

    -- trying to sign the multisig transaction before importing the transaction
    -- funding the account. This should return the original transaction
    cmdSignTx "signms" (decode' $ fromJust $ hexToBS partialTx) (SigAll False)
        >>= liftIO . assertEqual "Sign partial multisig without coins" 
            ( object [ "Tx"       .= T.pack partialTx
                     , "Complete" .= False
                     ]
            )

    -- Import the funding transaction into the wallet
    cmdImportTx fundingTx >>= liftIO . assertEqual "Importing funding tx"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
                         , T.pack "3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW"
                         , T.pack "3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR"
                         , T.pack "3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp"
                         ]
                     , "Value"      .= (630000:: Int)
                     ]
            ]
        )

    -- Import the funding transaction again. The process should be idempotent
    cmdImportTx fundingTx >>= liftIO . assertEqual "Importing funding tx"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
                         , T.pack "3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW"
                         , T.pack "3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR"
                         , T.pack "3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp"
                         ]
                     , "Value"      .= (630000:: Int)
                     ]
            ]
        )

    -- We should have 4 coins in the database
    cmdCoins "signms" >>= liftIO . assertEqual "Check coins after funding tx import" 
        (toJSON 
            [ object [ "TxID"    .= T.pack "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
                     , "Index"   .= (0 :: Int)
                     , "Value"   .= (100000 :: Int)
                     , "Script"  .= T.pack "a91491b00b8d4d4b8909d5d17fe8da3b09fbd64e003c87"
                     , "Redeem"  .= T.pack "522102690c830a595721558e2bf6c58f6ed269c3b9fa194523326bb26d9a20b0cf49532102c98a1bde30c9fd0b71e88792b512963ce8b956f8735dbb0b1a2d6da7f1385e8d2102e7166192bf2bb2433daad4ab396fc2dc09785df716ca992f8bf76ff0aed6695053ae"
                     , "Address" .= T.pack "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
                     ] 
            , object [ "TxID"    .= T.pack "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
                     , "Index"   .= (1 :: Int)
                     , "Value"   .= (200000 :: Int)
                     , "Script"  .= T.pack "a91488fb2eb63c1f992d801f538340180527510464c787"
                     , "Redeem"  .= T.pack "5221023206a385544defd500a54d3d3fd8982d35fa7f877fa721beb59e440186183e8a210352b7c1f82593abebcb4ad0bbf28a4317b49efc1cc3e647453c09c6375122e8f621035c9ca1f7825d2cf025f42e636f57f193dbaae5c18b08dca10bf996ddb58eb8e853ae"
                     , "Address" .= T.pack "3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW"
                     ] 
            , object [ "TxID"    .= T.pack "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
                     , "Index"   .= (2 :: Int)
                     , "Value"   .= (150000 :: Int)
                     , "Script"  .= T.pack "a9148c0ad01947abab4985837a24be0d2141dcba063987"
                     , "Redeem"  .= T.pack "522102779d361a5d534dfca9d480eb60a1b14741a98d29f5c984fc1afd68a8c50981232102f579364c0d0971ec9ae52f2fc870204bce00438be1b6fa695d27c9d01cfb0956210383787221b68f601aa4695c27e7eebb0d15de2ed7ef7b9981fba8cad71ae2d84253ae"
                     , "Address" .= T.pack "3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR"
                     ] 
            , object [ "TxID"    .= T.pack "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
                     , "Index"   .= (3 :: Int)
                     , "Value"   .= (180000 :: Int)
                     , "Script"  .= T.pack "a91460c1eb9034130684ece4594384e984325d1280ad87"
                     , "Redeem"  .= T.pack "52210285bd8161363c6e2d2c075e08ed8a956c4706ccd77497a31327bf92b2208c3587210286e3177a8ca61d2d9426b4230735631e8552cc4d6e87e1277960461b0d26aac42103e2e138589e064f347238c2ca46c1d7deb8dd9472d065d7c5cb0f91aa5cc210a953ae"
                     , "Address" .= T.pack "3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp"
                     ] 
            ]
        )

    -- Import the partially signed transaction into the wallet
    -- This should yield a partial transaction and no output coins
    cmdImportTx (decode' $ fromJust $ hexToBS $ partialTx) >>= 
        liftIO . assertEqual "Importing partial tx 1"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                        [ T.pack "13LjjLQGGiTL8AYMbYqBmQVyAMyQnjPZK3"
                        , T.pack "1MK3xFQSekQPuety1oaVTmvLRusFYsTq3d"
                        ]
                    , "Value"      .= (-450000 :: Int)
                    , "Partial"    .= True
                    ]
            ]
        )

    -- Re-importing the partial transaction should be an idempotent process
    cmdImportTx (decode' $ fromJust $ hexToBS $ partialTx) >>= 
        liftIO . assertEqual "Importing partial tx 2"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                        [ T.pack "13LjjLQGGiTL8AYMbYqBmQVyAMyQnjPZK3"
                        , T.pack "1MK3xFQSekQPuety1oaVTmvLRusFYsTq3d"
                        ]
                    , "Value"      .= (-450000 :: Int)
                    , "Partial"    .= True
                    ]
            ]
        )

    -- After importing the partially signed transaction in the wallet, we should
    -- have some of the coins in "reserved" status. Additionally, the change
    -- coin should not be displayed here as importing partial transactions does
    -- not produce coins (would not make sense as TxID is wrong)
    cmdCoins "signms" >>= liftIO . assertEqual "Check coins after importing partial tx" 
        (toJSON 
            [ object [ "TxID"    .= T.pack "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
                     , "Index"   .= (0 :: Int)
                     , "Value"   .= (100000 :: Int)
                     , "Script"  .= T.pack "a91491b00b8d4d4b8909d5d17fe8da3b09fbd64e003c87"
                     , "Redeem"  .= T.pack "522102690c830a595721558e2bf6c58f6ed269c3b9fa194523326bb26d9a20b0cf49532102c98a1bde30c9fd0b71e88792b512963ce8b956f8735dbb0b1a2d6da7f1385e8d2102e7166192bf2bb2433daad4ab396fc2dc09785df716ca992f8bf76ff0aed6695053ae"
                     , "Address" .= T.pack "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
                     ] 
            ]
        )

    -- Now we should have the funding transaction followed by a
    -- a partially signed multisig transaction
    cmdListTx "signms" >>= liftIO . assertEqual "Final tx check MS"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
                         , T.pack "3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW"
                         , T.pack "3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR"
                         , T.pack "3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp"
                         ]
                     , "Value"      .= (630000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "13LjjLQGGiTL8AYMbYqBmQVyAMyQnjPZK3"
                         , T.pack "1MK3xFQSekQPuety1oaVTmvLRusFYsTq3d"
                         ]
                     , "Value"      .= (-450000 :: Int)
                     , "Partial"    .= True
                     ]
            ]
        )


    let f (Entity _ c) = ( dbCoinTxid c, dbCoinPos c
                         , dbCoinValue c, dbCoinScript c
                         , dbCoinRdmScript c, dbCoinAddress c
                         , dbCoinStatus c, dbCoinOrphan c
                         )
        g (Entity _ t) = ( dbTxTxid t, dbTxRecipients t
                         , dbTxValue t, dbTxOrphan t, dbTxPartial t
                         )

    (Entity msi _) <- dbGetAcc "signms"

    -- Checking the coins directly in the database
    ((map f) <$> selectList [DbCoinAccount ==. msi] [Asc DbCoinCreated]) >>= 
        liftIO . assertEqual "Check DB coins after importing Partial tx"
            [ ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , 0, 100000, "a91491b00b8d4d4b8909d5d17fe8da3b09fbd64e003c87"
              , Just "522102690c830a595721558e2bf6c58f6ed269c3b9fa194523326bb26d9a20b0cf49532102c98a1bde30c9fd0b71e88792b512963ce8b956f8735dbb0b1a2d6da7f1385e8d2102e7166192bf2bb2433daad4ab396fc2dc09785df716ca992f8bf76ff0aed6695053ae"
              , "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
              , Unspent
              , False
              )
            , ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , 1, 200000, "a91488fb2eb63c1f992d801f538340180527510464c787"
              , Just "5221023206a385544defd500a54d3d3fd8982d35fa7f877fa721beb59e440186183e8a210352b7c1f82593abebcb4ad0bbf28a4317b49efc1cc3e647453c09c6375122e8f621035c9ca1f7825d2cf025f42e636f57f193dbaae5c18b08dca10bf996ddb58eb8e853ae"
              , "3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW"
              , Reserved "74ea8680000dd5e4f0122e47c73de7b0b02aae478a03930c5f547f67ed3dabcb"
              , False
              )
            , ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , 2, 150000, "a9148c0ad01947abab4985837a24be0d2141dcba063987"
              , Just "522102779d361a5d534dfca9d480eb60a1b14741a98d29f5c984fc1afd68a8c50981232102f579364c0d0971ec9ae52f2fc870204bce00438be1b6fa695d27c9d01cfb0956210383787221b68f601aa4695c27e7eebb0d15de2ed7ef7b9981fba8cad71ae2d84253ae"
              , "3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR"
              , Reserved "74ea8680000dd5e4f0122e47c73de7b0b02aae478a03930c5f547f67ed3dabcb"
              , False
              )
            , ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , 3, 180000, "a91460c1eb9034130684ece4594384e984325d1280ad87"
              , Just "52210285bd8161363c6e2d2c075e08ed8a956c4706ccd77497a31327bf92b2208c3587210286e3177a8ca61d2d9426b4230735631e8552cc4d6e87e1277960461b0d26aac42103e2e138589e064f347238c2ca46c1d7deb8dd9472d065d7c5cb0f91aa5cc210a953ae"
              , "3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp"
              , Reserved "74ea8680000dd5e4f0122e47c73de7b0b02aae478a03930c5f547f67ed3dabcb"
              , False
              )
            ]

    -- Checking the transactions directly in the database
    ((map g) <$> selectList [DbTxAccount ==. msi] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Check DB transactions after importing Partial tx"
            [ ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , [ "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
                , "3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW"
                , "3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR"
                , "3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp"
                ]
              , 630000 , False, False
              )
            , ( "74ea8680000dd5e4f0122e47c73de7b0b02aae478a03930c5f547f67ed3dabcb"
              , [ "13LjjLQGGiTL8AYMbYqBmQVyAMyQnjPZK3"
                , "1MK3xFQSekQPuety1oaVTmvLRusFYsTq3d"
                ]
              , -450000, False, True
              )
            ]

    -- Completing a multisig transaction
    cmdSignTx "signms" (decode' $ fromJust $ hexToBS partialTx) (SigAll False) 
        >>= liftIO . assertEqual "Sign partial multisig" 
            ( object [ "Tx"       .= T.pack finalTx
                     , "Complete" .= True
                     ]
            )

    -- this should return the partial signature as the account is wrong
    cmdSignTx "ms1" (decode' $ fromJust $ hexToBS partialTx) (SigAll False) 
        >>= liftIO . assertEqual "Sign partial multisig bad acc" 
            ( object [ "Tx"       .= T.pack partialTx
                     , "Complete" .= False
                     ]
            )

    -- Importing the full transaction into the wallet
    cmdImportTx (decode' $ fromJust $ hexToBS finalTx) >>= 
        liftIO . assertEqual "Final tx import"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                            [ T.pack "13LjjLQGGiTL8AYMbYqBmQVyAMyQnjPZK3"
                            , T.pack "1MK3xFQSekQPuety1oaVTmvLRusFYsTq3d"
                            ]
                        , "Value"      .= (-450000 :: Int)
                        ]
                ]
            )

    -- Importing the full transaction into the wallet (again)
    cmdImportTx (decode' $ fromJust $ hexToBS finalTx) >>= 
        liftIO . assertEqual "Final tx import again"
            ( toJSON
                [ object [ "Recipients" .= toJSON
                            [ T.pack "13LjjLQGGiTL8AYMbYqBmQVyAMyQnjPZK3"
                            , T.pack "1MK3xFQSekQPuety1oaVTmvLRusFYsTq3d"
                            ]
                        , "Value"      .= (-450000 :: Int)
                        ]
                ]
            )

    -- The change coin should now be there
    cmdCoins "signms" >>= liftIO . assertEqual "Check coins after importing final tx" 
        (toJSON 
            [ object [ "TxID"    .= T.pack "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
                     , "Index"   .= (0 :: Int)
                     , "Value"   .= (100000 :: Int)
                     , "Script"  .= T.pack "a91491b00b8d4d4b8909d5d17fe8da3b09fbd64e003c87"
                     , "Redeem"  .= T.pack "522102690c830a595721558e2bf6c58f6ed269c3b9fa194523326bb26d9a20b0cf49532102c98a1bde30c9fd0b71e88792b512963ce8b956f8735dbb0b1a2d6da7f1385e8d2102e7166192bf2bb2433daad4ab396fc2dc09785df716ca992f8bf76ff0aed6695053ae"
                     , "Address" .= T.pack "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
                     ] 
            , object [ "TxID"    .= T.pack "a7274a15719099c5de37741bfd70efa15bb22a9de5507d966ccdf528a4f8f4c3"
                     , "Index"   .= (2 :: Int)
                     , "Value"   .= (80000 :: Int)
                     , "Script"  .= T.pack "a914737e1e10bbf4290c82681745b5a54449ca83d18487"
                     , "Redeem"  .= T.pack "5221021190e8331245f9455d0b027cd9f53e2e5f530ffa48aaa4f6b9fc7657c8cd5ebe21030e08ad2233845f90e958988768b42f8e53d358efc371149049a5399ae0d3b334210380f8240eb12a1bbe20c2f441d6c2216d5eb84bbb4b926aa801180de13dbdf7c553ae"
                     , "Address" .= T.pack "3CDgiQ2TnKvy1AovxwFy2jsDqURN8bq856"
                     ] 
            ]
        )

    -- The transaction list should be the funding transaction followed by
    -- the multisig spending transaction
    cmdListTx "signms" >>= liftIO . assertEqual "Check tx after importing final tx"
        ( toJSON
            [ object [ "Recipients" .= toJSON
                         [ T.pack "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
                         , T.pack "3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW"
                         , T.pack "3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR"
                         , T.pack "3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp"
                         ]
                     , "Value"      .= (630000 :: Int)
                     ]
            , object [ "Recipients" .= toJSON
                         [ T.pack "13LjjLQGGiTL8AYMbYqBmQVyAMyQnjPZK3"
                         , T.pack "1MK3xFQSekQPuety1oaVTmvLRusFYsTq3d"
                         ]
                     , "Value"      .= (-450000 :: Int)
                     ]
            ]
        )

    -- Checking the coins directly in the database
    ((map f) <$> selectList [DbCoinAccount ==. msi] [Asc DbCoinCreated]) >>= 
        liftIO . assertEqual "Check DB coins after importing Final tx"
            [ ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , 0, 100000, "a91491b00b8d4d4b8909d5d17fe8da3b09fbd64e003c87"
              , Just "522102690c830a595721558e2bf6c58f6ed269c3b9fa194523326bb26d9a20b0cf49532102c98a1bde30c9fd0b71e88792b512963ce8b956f8735dbb0b1a2d6da7f1385e8d2102e7166192bf2bb2433daad4ab396fc2dc09785df716ca992f8bf76ff0aed6695053ae"
              , "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
              , Unspent
              , False
              )
            , ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , 1, 200000, "a91488fb2eb63c1f992d801f538340180527510464c787"
              , Just "5221023206a385544defd500a54d3d3fd8982d35fa7f877fa721beb59e440186183e8a210352b7c1f82593abebcb4ad0bbf28a4317b49efc1cc3e647453c09c6375122e8f621035c9ca1f7825d2cf025f42e636f57f193dbaae5c18b08dca10bf996ddb58eb8e853ae"
              , "3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW"
              , Spent "a7274a15719099c5de37741bfd70efa15bb22a9de5507d966ccdf528a4f8f4c3"
              , False
              )
            , ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , 2, 150000, "a9148c0ad01947abab4985837a24be0d2141dcba063987"
              , Just "522102779d361a5d534dfca9d480eb60a1b14741a98d29f5c984fc1afd68a8c50981232102f579364c0d0971ec9ae52f2fc870204bce00438be1b6fa695d27c9d01cfb0956210383787221b68f601aa4695c27e7eebb0d15de2ed7ef7b9981fba8cad71ae2d84253ae"
              , "3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR"
              , Spent "a7274a15719099c5de37741bfd70efa15bb22a9de5507d966ccdf528a4f8f4c3"
              , False
              )
            , ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , 3, 180000, "a91460c1eb9034130684ece4594384e984325d1280ad87"
              , Just "52210285bd8161363c6e2d2c075e08ed8a956c4706ccd77497a31327bf92b2208c3587210286e3177a8ca61d2d9426b4230735631e8552cc4d6e87e1277960461b0d26aac42103e2e138589e064f347238c2ca46c1d7deb8dd9472d065d7c5cb0f91aa5cc210a953ae"
              , "3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp"
              , Spent "a7274a15719099c5de37741bfd70efa15bb22a9de5507d966ccdf528a4f8f4c3"
              , False
              )
            , ( "a7274a15719099c5de37741bfd70efa15bb22a9de5507d966ccdf528a4f8f4c3"
              , 2, 80000, "a914737e1e10bbf4290c82681745b5a54449ca83d18487"
              , Just "5221021190e8331245f9455d0b027cd9f53e2e5f530ffa48aaa4f6b9fc7657c8cd5ebe21030e08ad2233845f90e958988768b42f8e53d358efc371149049a5399ae0d3b334210380f8240eb12a1bbe20c2f441d6c2216d5eb84bbb4b926aa801180de13dbdf7c553ae"
              , "3CDgiQ2TnKvy1AovxwFy2jsDqURN8bq856"
              , Unspent
              , False
              )
            ]

    -- Checking the transactions directly in the database
    ((map g) <$> selectList [DbTxAccount ==. msi] [Asc DbTxCreated]) >>=
        liftIO . assertEqual "Check DB transactions after importing Final tx"
            [ ( "62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589"
              , [ "3EyLoBudu2fNY7hnQDX7iZ3kn1d9wyPc2E"
                , "3EBJj6Z2FrrGUytJabTrJRD6mxCgF3d7JW"
                , "3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR"
                , "3AWd6mZHrvMbocVRp752ExTGnUhh1huWQp"
                ]
              , 630000 , False, False
              )
            , ( "a7274a15719099c5de37741bfd70efa15bb22a9de5507d966ccdf528a4f8f4c3"
              , [ "13LjjLQGGiTL8AYMbYqBmQVyAMyQnjPZK3"
                , "1MK3xFQSekQPuety1oaVTmvLRusFYsTq3d"
                ]
              , -450000, False, False
              )
            ]

testUtil :: ( PersistStore m, PersistUnique m, PersistQuery m
            , PersistMonadBackend m ~ SqlBackend
            ) 
         => EitherT String m ()
testUtil = do 

    cmdBuildRawTx "[{\"txid\":\"0100000000000000000000000000000000000000000000000000000000000000\",\"vout\":10},{\"txid\":\"0200000000000000000000000000000000000000000000000000000000000000\",\"vout\":11}]" "{\"1EWdRnLVsncoJjrfShHQxPDJPZNGNGFKgx\":100000,\"3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR\":200000}" >>= liftIO . assertEqual "Build Raw Tx"
        (toJSON $ object ["Tx" .= T.pack "010000000200000000000000000000000000000000000000000000000000000000000000010a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000020b00000000ffffffff02a0860100000000001976a91494341b2515efda20f26d37a2f4f5abd424cf71f688ac400d03000000000017a9148c0ad01947abab4985837a24be0d2141dcba06398700000000"])

    let partialTx = "01000000038935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76202000000b6004830450221009d876833374da1714aa42945b73fe2af9ee37fdf32b4db9dd10297c0a9a18257022065618d04ead4ba5e4201bf15f149f1429e83173d42e31246d3164f2072e6605901004c69522102779d361a5d534dfca9d480eb60a1b14741a98d29f5c984fc1afd68a8c50981232102f579364c0d0971ec9ae52f2fc870204bce00438be1b6fa695d27c9d01cfb0956210383787221b68f601aa4695c27e7eebb0d15de2ed7ef7b9981fba8cad71ae2d84253aeffffffff8935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76203000000b600483045022100f8f9274fcf04200031578f5bfa0ecd108f5c945d7efef5f4fe519943d945594502200941f22088458750894005366a74857b72fb59197405bd2298947d96456d165b01004c6952210285bd8161363c6e2d2c075e08ed8a956c4706ccd77497a31327bf92b2208c3587210286e3177a8ca61d2d9426b4230735631e8552cc4d6e87e1277960461b0d26aac42103e2e138589e064f347238c2ca46c1d7deb8dd9472d065d7c5cb0f91aa5cc210a953aeffffffff8935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76201000000b50047304402200469180f9e94bf6d1d03ce07411bfd107b78f2fb1b1a862fc39dfeece417d14b02206696f963f97d3a6aaddc295c8eaf1846fef07f44c46d3aa97f09a4c0b72476c101004c695221023206a385544defd500a54d3d3fd8982d35fa7f877fa721beb59e440186183e8a210352b7c1f82593abebcb4ad0bbf28a4317b49efc1cc3e647453c09c6375122e8f621035c9ca1f7825d2cf025f42e636f57f193dbaae5c18b08dca10bf996ddb58eb8e853aeffffffff03e0930400000000001976a91419abd2efb4cd44b132ffd6206aa35e60f9d3e4b988ace0220200000000001976a914decc77b87d2199a51532034ad63f59cae6e6c4f588ac803801000000000017a914737e1e10bbf4290c82681745b5a54449ca83d1848700000000"

    let resultTx = "01000000038935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76202000000fdfd00004830450221009d876833374da1714aa42945b73fe2af9ee37fdf32b4db9dd10297c0a9a18257022065618d04ead4ba5e4201bf15f149f1429e83173d42e31246d3164f2072e6605901473044022065316243de4edd6e1741580a11489a5445b4fc35efcb13aa6189f1a524f6745a022003fdf5273c90ac7d906cba33f42661dcac45e80aab9aecd4fcd5ed5e9595c239014c69522102779d361a5d534dfca9d480eb60a1b14741a98d29f5c984fc1afd68a8c50981232102f579364c0d0971ec9ae52f2fc870204bce00438be1b6fa695d27c9d01cfb0956210383787221b68f601aa4695c27e7eebb0d15de2ed7ef7b9981fba8cad71ae2d84253aeffffffff8935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76203000000b600483045022100f8f9274fcf04200031578f5bfa0ecd108f5c945d7efef5f4fe519943d945594502200941f22088458750894005366a74857b72fb59197405bd2298947d96456d165b01004c6952210285bd8161363c6e2d2c075e08ed8a956c4706ccd77497a31327bf92b2208c3587210286e3177a8ca61d2d9426b4230735631e8552cc4d6e87e1277960461b0d26aac42103e2e138589e064f347238c2ca46c1d7deb8dd9472d065d7c5cb0f91aa5cc210a953aeffffffff8935da5b1084b96a26d931aa9a6e9c844191c014c190d7981979eb977c89e76201000000fdfd000047304402200469180f9e94bf6d1d03ce07411bfd107b78f2fb1b1a862fc39dfeece417d14b02206696f963f97d3a6aaddc295c8eaf1846fef07f44c46d3aa97f09a4c0b72476c101483045022100e865ba910c96823cc9ddf6b65d62f6d107ca5589a866f3814d048ada70a01b3102201025101604ccf2f639a7f7176517665656b04c9a531d3e542eb495095148b802014c695221023206a385544defd500a54d3d3fd8982d35fa7f877fa721beb59e440186183e8a210352b7c1f82593abebcb4ad0bbf28a4317b49efc1cc3e647453c09c6375122e8f621035c9ca1f7825d2cf025f42e636f57f193dbaae5c18b08dca10bf996ddb58eb8e853aeffffffff03e0930400000000001976a91419abd2efb4cd44b132ffd6206aa35e60f9d3e4b988ace0220200000000001976a914decc77b87d2199a51532034ad63f59cae6e6c4f588ac803801000000000017a914737e1e10bbf4290c82681745b5a54449ca83d1848700000000"

    let sigi = concat
            [ "[{"
            , "\"txid\":\"62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589\","
            , "\"vout\":2,"
            , "\"scriptPubKey\":\"a9148c0ad01947abab4985837a24be0d2141dcba063987\","
            , "\"scriptRedeem\":\"522102779d361a5d534dfca9d480eb60a1b14741a98d29f5c984fc1afd68a8c50981232102f579364c0d0971ec9ae52f2fc870204bce00438be1b6fa695d27c9d01cfb0956210383787221b68f601aa4695c27e7eebb0d15de2ed7ef7b9981fba8cad71ae2d84253ae\""
            , "},{"
            , "\"txid\":\"62e7897c97eb791998d790c114c09141849c6e9aaa31d9266ab984105bda3589\","
            , "\"vout\":1,"
            , "\"scriptPubKey\":\"a91488fb2eb63c1f992d801f538340180527510464c787\","
            , "\"scriptRedeem\":\"5221023206a385544defd500a54d3d3fd8982d35fa7f877fa721beb59e440186183e8a210352b7c1f82593abebcb4ad0bbf28a4317b49efc1cc3e647453c09c6375122e8f621035c9ca1f7825d2cf025f42e636f57f193dbaae5c18b08dca10bf996ddb58eb8e853ae\""
            , "}]"
            ]

    -- WIF for 3ETVUh7mn1sSiLrhUQYMByfuo32DauHKdR (input 0)
    let prv = concat
            [ "["
            , "\"L4rxfXmwUDpmkpfmUAaJo7ChfPgAAj18pdpF8GTVkJRheJZaFikf\","
            , "\"L5ZencGKZqtiDk2DjFn23PjMdzGo9ZNpDw5wpcgN2cX1Qzjg6zzr\""
            , "]"
            ]
        tx  = decode' $ fromJust $ hexToBS partialTx

    cmdSignRawTx tx sigi prv (SigAll False) >>=
        liftIO . assertEqual "Sign raw transaction"
        ( object [ (T.pack "Tx") .= T.pack resultTx
                 , (T.pack "Complete") .= False
                 ]
        )