View on GitHub
File Changes

                      
-- | Port number with a tag for describing what it is used for
newtype Port (tag :: Symbol) = Port { getPort :: Int }
-
    deriving stock (Eq, Show, Generic)
-
    deriving newtype (Enum, Ord)
+
    deriving stock (Eq, Generic)
+
    deriving newtype (Enum, Ord, Show)

                      
-- NOTE
-- TCP port ranges from [[-1;65535]] \ {0}
    , direction
    , feeEstimator
    , inputs
-
    , jormungandrBaseUrl
    , passphraseLastUpdate
    , state
    , status
    , postExternalTransactionViaCLI
    ) where

                      
+
import Cardano.CLI
+
    ( Port (..) )
import Cardano.Wallet.Api.Types
    ( AddressAmount
    , ApiAddress
    ( Manager )
import Network.HTTP.Types.Method
    ( Method )
-
import Network.Wai.Handler.Warp
-
    ( Port )
import Numeric.Natural
    ( Natural )
import Prelude hiding
    _get = _feeEstimator
    _set (ctx, v) = ctx { _feeEstimator = v }

                      
-
jormungandrBaseUrl
-
    :: Lens' (Context t) Text
-
jormungandrBaseUrl =
-
    lens _get _set
-
  where
-
    _get = _jormungandrBaseUrl
-
    _set (ctx, v) = ctx { _jormungandrBaseUrl = v }
-

                      
passphraseLastUpdate
    :: HasType (Maybe (ApiT WalletPassphraseInfo)) s
    => Lens' s (Maybe Text)

                      
-- | Wait for a booting wallet server to start. Wait up to 30s or fail.
waitForServer
-
    :: forall t ctx. (HasType Port ctx, KnownCommand t)
+
    :: forall t ctx. (HasType (Port "wallet") ctx, KnownCommand t)
    => ctx
    -> IO ()
waitForServer ctx = void $ retrying
    (["mnemonic", "generate"] ++ args)

                      
createWalletViaCLI
-
    :: forall t s. (HasType Port s, KnownCommand t)
+
    :: forall t s. (HasType (Port "wallet") s, KnownCommand t)
    => s
    -> [String]
    -> String
    -> IO (ExitCode, String, Text)
createWalletViaCLI ctx args mnemonics secondFactor passphrase = do
    let portArgs =
-
            [ "--port", show (ctx ^. typed @Port) ]
+
            [ "--port", show (ctx ^. typed @(Port "wallet")) ]
    let fullArgs =
            [ "wallet", "create" ] ++ portArgs ++ args
    let process = proc' (commandName @t) fullArgs
        return (c, T.unpack out, err)

                      
deleteWalletViaCLI
-
    :: forall t r s. (CmdResult r, KnownCommand t, HasType Port s)
+
    :: forall t r s. (CmdResult r, KnownCommand t, HasType (Port "wallet") s)
    => s
    -> String
    -> IO r
deleteWalletViaCLI ctx walId = cardanoWalletCLI @t
-
    ["wallet", "delete", "--port", show (ctx ^. typed @Port), walId ]
+
    ["wallet", "delete", "--port", show (ctx ^. typed @(Port "wallet")), walId ]

                      
getWalletViaCLI
-
    :: forall t r s. (CmdResult r, KnownCommand t, HasType Port s)
+
    :: forall t r s. (CmdResult r, KnownCommand t, HasType (Port "wallet") s)
    => s
    -> String
    -> IO r
getWalletViaCLI ctx walId = cardanoWalletCLI @t
-
    ["wallet", "get", "--port", show (ctx ^. typed @Port) , walId ]
+
    ["wallet", "get", "--port", show (ctx ^. typed @(Port "wallet")) , walId ]

                      
getWalletUtxoStatisticsViaCLI
-
    :: forall t r s. (CmdResult r, KnownCommand t, HasType Port s)
+
    :: forall t r s. (CmdResult r, KnownCommand t, HasType (Port "wallet") s)
    => s
    -> String
    -> IO r
getWalletUtxoStatisticsViaCLI ctx walId = cardanoWalletCLI @t
-
    ["wallet", "utxo", "--port", show (ctx ^. typed @Port) , walId ]
+
    ["wallet", "utxo", "--port", show (ctx ^. typed @(Port "wallet")) , walId ]

                      
listAddressesViaCLI
-
    :: forall t r s. (CmdResult r, KnownCommand t, HasType Port s)
+
    :: forall t r s. (CmdResult r, KnownCommand t, HasType (Port "wallet") s)
    => s
    -> [String]
    -> IO r
listAddressesViaCLI ctx args = cardanoWalletCLI @t
-
    (["address", "list", "--port", show (ctx ^. typed @Port)] ++ args)
+
    (["address", "list", "--port", show (ctx ^. typed @(Port "wallet"))] ++ args)

                      
listWalletsViaCLI
-
    :: forall t r s. (CmdResult r, KnownCommand t, HasType Port s)
+
    :: forall t r s. (CmdResult r, KnownCommand t, HasType (Port "wallet") s)
    => s
    -> IO r
listWalletsViaCLI ctx = cardanoWalletCLI @t
-
    ["wallet", "list", "--port", show (ctx ^. typed @Port) ]
+
    ["wallet", "list", "--port", show (ctx ^. typed @(Port "wallet")) ]

                      
updateWalletNameViaCLI
-
    :: forall t r s. (CmdResult r, KnownCommand t, HasType Port s)
+
    :: forall t r s. (CmdResult r, KnownCommand t, HasType (Port "wallet") s)
    => s
    -> [String]
    -> IO r
updateWalletNameViaCLI ctx args = cardanoWalletCLI @t
-
    (["wallet", "update", "name", "--port", show (ctx ^. typed @Port)] ++ args)
+
    (["wallet", "update", "name", "--port", walletPort] ++ args)
+
  where
+
    walletPort = show (ctx ^. typed @(Port "wallet"))

                      
updateWalletPassphraseViaCLI
-
    :: forall t s. (KnownCommand t, HasType Port s)
+
    :: forall t s. (KnownCommand t, HasType (Port "wallet") s)
    => s
    -> String
        -- ^ Wallet id
updateWalletPassphraseViaCLI ctx wid ppOld ppNew ppNewConfirm = do
    let process = proc' (commandName @t)
            [ "wallet", "update", "passphrase"
-
            , "--port", show (ctx ^. typed @Port)
+
            , "--port", show (ctx ^. typed @(Port "wallet"))
            , wid
            ]
    withCreateProcess process $
            pure (c, out, err)

                      
postTransactionViaCLI
-
    :: forall t s. (HasType Port s, KnownCommand t)
+
    :: forall t s. (HasType (Port "wallet") s, KnownCommand t)
    => s
    -> String
    -> [String]
    -> IO (ExitCode, String, Text)
postTransactionViaCLI ctx passphrase args = do
    let portArgs =
-
            ["--port", show (ctx ^. typed @Port)]
+
            ["--port", show (ctx ^. typed @(Port "wallet"))]
    let fullArgs =
            ["transaction", "create"] ++ portArgs ++ args
    let process = proc' (commandName @t) fullArgs
        return (c, T.unpack out, err)

                      
postTransactionFeeViaCLI
-
    :: forall t s. (HasType Port s, KnownCommand t)
+
    :: forall t s. (HasType (Port "wallet") s, KnownCommand t)
    => s
    -> [String]
    -> IO (ExitCode, String, Text)
postTransactionFeeViaCLI ctx args = do
    let portArgs =
-
            ["--port", show (ctx ^. typed @Port)]
+
            ["--port", show (ctx ^. typed @(Port "wallet"))]
    let fullArgs =
            ["transaction", "fees"] ++ portArgs ++ args
    let process = proc' (commandName @t) fullArgs
        return (c, T.unpack out, err)

                      
listTransactionsViaCLI
-
    :: forall t r s . (CmdResult r, HasType Port s, KnownCommand t)
+
    :: forall t r s . (CmdResult r, HasType (Port "wallet") s, KnownCommand t)
    => s
    -> [String]
    -> IO r
listTransactionsViaCLI ctx args = cardanoWalletCLI @t $ join
    [ ["transaction", "list"]
-
    , ["--port", show (ctx ^. typed @Port)]
+
    , ["--port", show (ctx ^. typed @(Port "wallet"))]
    , args
    ]

                      
postExternalTransactionViaCLI
-
    :: forall t r s . (CmdResult r, HasType Port s, KnownCommand t)
+
    :: forall t r s . (CmdResult r, HasType (Port "wallet") s, KnownCommand t)
    => s

                      
import Prelude

                      
+
import Cardano.CLI
+
    ( Port (..) )
import Control.Monad.Catch
    ( Exception (..), MonadCatch (..), throwM )
import Control.Monad.IO.Class
    ( Method )
import Network.HTTP.Types.Status
    ( status500 )
-
import Network.Wai.Handler.Warp
-
    ( Port )
import Numeric.Natural
    ( Natural )
import Test.Integration.Faucet
    , _manager
        :: (Text, Manager)
        -- ^ The underlying BaseUrl and Manager used by the Wallet Client
-
    , _port
-
        :: Port
+
    , _walletPort
+
        :: Port "wallet"
        -- ^ Server TCP port
-
    , _jormungandrBaseUrl
-
        :: Text
+
    , _nodePort
+
        :: Port "node"
        -- ^ Jormungandr REST API port
    , _faucet
        :: Faucet
import Prelude

                      
import Cardano.CLI
-
    ( getPort )
+
    ( Port (..), getPort )
import Control.Monad
    ( forM_, void )
import Data.Generics.Internal.VL.Lens
    ( over, (^.) )
import Data.Generics.Product.Typed
    ( HasType, typed )
-
import Network.Wai.Handler.Warp
-
    ( Port )
import System.Command
    ( Stderr (..), Stdout (..) )
import System.Exit
                    )

                      
specCommon
-
    :: forall t s. (HasType Port s, KnownCommand t)
+
    :: forall t s. (HasType (Port "wallet") s, KnownCommand t)
    => SpecWith s
specCommon = do
+
    let overPort :: forall sym. HasType (Port sym) s => (Int -> Int) -> s -> s
+
        overPort fn = over (typed @(Port sym)) (\(Port p) -> Port $ fn p)
+

                      
    it "PORT_01 - Can't reach server with wrong port (wallet list)" $ \ctx -> do
-
        let ctx' = over (typed @Port) (+1) ctx
+
        let ctx' = overPort @"wallet" (+1) ctx
        (_ :: ExitCode, Stdout (_ :: String), Stderr err) <-
            listWalletsViaCLI @t ctx'
        err `shouldContain` errConnectionRefused

                      
    it "PORT_01 - Can't reach server with wrong port (wallet create)" $ \ctx -> do
-
        let ctx' = over (typed @Port) (+1) ctx
+
        let ctx' = overPort @"wallet" (+1) ctx
        let name = "Wallet created via CLI"
        Stdout mnemonics <- generateMnemonicsViaCLI @t ["--size", "15"]
        let pwd = "Secure passphrase"
        T.unpack err `shouldContain` errConnectionRefused

                      
    it "PORT_01 - Can't reach server with wrong port (wallet get)" $ \ctx -> do
-
        let ctx' = over (typed @Port) (+1) ctx
+
        let ctx' = overPort @"wallet" (+1) ctx
        let wid = replicate 40 '0'
        (_ :: ExitCode, Stdout (_ :: String), Stderr err) <-
            getWalletViaCLI @t ctx' wid
        err `shouldContain` errConnectionRefused

                      
    it "PORT_01 - Can't reach server with wrong port (wallet delete)" $ \ctx -> do
-
        let ctx' = over (typed @Port) (+1) ctx
+
        let ctx' = overPort @"wallet" (+1) ctx
        let wid = replicate 40 '0'
        (_ :: ExitCode, Stdout (_ :: String), Stderr err) <-
            deleteWalletViaCLI @t ctx' wid
        err `shouldContain` errConnectionRefused

                      
    it "PORT_01 - Can't reach server with wrong port (wallet update)" $ \ctx -> do
-
        let ctx' = over (typed @Port) (+1) ctx
+
        let ctx' = overPort @"wallet" (+1) ctx
        let wid = replicate 40 '0'
        (_ :: ExitCode, Stdout (_ :: String), Stderr err) <-
            updateWalletNameViaCLI @t ctx' [wid, "My Wallet"]
        err `shouldContain` errConnectionRefused

                      
    it "PORT_01 - Can't reach server with wrong port (transction create)" $ \ctx -> do
-
        let ctx' = over (typed @Port) (+1) ctx
+
        let ctx' = overPort @"wallet" (+1) ctx
        let addr =
                "37btjrVyb4KFjfnPUjgDKLiATLxgwBbeMAEr4vxgkq4Ea5nR6evtX99x2\
                \QFcF8ApLM4aqCLGvhHQyRJ4JHk4zVKxNeEtTJaPCeB86LndU2YvKUTEEm"
        T.unpack err `shouldContain` errConnectionRefused

                      
    it "PORT_01 - Can't reach server with wrong port (address list)" $ \ctx -> do
-
        let ctx' = over (typed @Port) (+1) ctx
+
        let ctx' = overPort @"wallet" (+1) ctx
        let wid = replicate 40 '0'
        (_ :: ExitCode, Stdout (_ :: String), Stderr err) <-
            listAddressesViaCLI @t ctx' [wid]
        err `shouldContain` errConnectionRefused

                      
specWithDefaultPort
-
    :: forall t s. (HasType Port s, KnownCommand t)
+
    :: forall t s. (HasType (Port "wallet") s, KnownCommand t)
    => SpecWith s
specWithDefaultPort = do
    it "PORT_02 - Can omit --port when server uses default port (wallet list)" $ \_ -> do
        err `shouldNotContain` errConnectionRefused

                      
specWithRandomPort
-
    :: forall t s. (HasType Port s, KnownCommand t)
-
    => Port
+
    :: forall t s. (HasType (Port "wallet") s, KnownCommand t)
+
    => Port "wallet"
    -> SpecWith s
specWithRandomPort defaultPort = do
    it "PORT_03 - random port != default port" $ \ctx -> do
-
        (ctx ^. typed @Port) `shouldNotBe` defaultPort
+
        (ctx ^. typed @(Port "wallet")) `shouldNotBe` defaultPort
        return () :: IO () -- Ease the type inference for the line above

                      
    it "PORT_03 - Cannot omit --port when server uses random port (wallet list)" $ \_ -> do

                      
import Prelude

                      
+
import Cardano.CLI
+
    ( Port )
import Cardano.Wallet.Api.Types
    ( ApiFee, ApiTransaction, ApiWallet, getApiT, insertedAt, time )
import Cardano.Wallet.Primitive.Types
    ( UTCTime )
import Data.Time.Utils
    ( utcTimePred, utcTimeSucc )
-
import Network.Wai.Handler.Warp
-
    ( Port )
import Numeric.Natural
    ( Natural )
import System.Command
        forM_ falseWalletIds $ \(title, walId) -> it title $ \ctx -> do
            wDest <- emptyWallet ctx
            addrs:_ <- listAddresses ctx wDest
-
            let port = show $ ctx ^. typed @Port
+
            let port = show $ ctx ^. typed @(Port "wallet")
            let addr = encodeAddress (Proxy @t) (getApiT $ fst $ addrs ^. #id)
            let args =
                    [ "transaction", "create", "--port", port
        wSrc <- emptyWallet ctx
        wDest <- emptyWallet ctx
        addrs:_ <- listAddresses ctx wDest
-
        let port = T.pack $ show $ ctx ^. typed @Port
+
        let port = T.pack $ show $ ctx ^. typed @(Port "wallet")
        let addr = encodeAddress (Proxy @t) (getApiT $ fst $ addrs ^. #id)
        let args = T.unpack <$>
                [ "transaction", "create", "--port", port
        wDest <- emptyWallet ctx
        addrs:_ <- listAddresses ctx wDest
        let addr = encodeAddress (Proxy @t) (getApiT $ fst $ addrs ^. #id)
-
        let port = T.pack $ show $ ctx ^. typed @Port
+
        let port = T.pack $ show $ ctx ^. typed @(Port "wallet")
        let args = T.unpack <$>
                [ "transaction", "create", "--port", port
                , wSrc ^. walletId, "--payment", "[email protected]" <> addr
    , aeson
    , async
    , cardano-crypto
+
    , cardano-wallet-cli
    , cardano-wallet-core
    , cardano-wallet-core-integration
    , cardano-wallet-http-bridge

                      
import Cardano.BM.Trace
    ( nullTracer )
+
import Cardano.CLI
+
    ( Port (..) )
import Cardano.Faucet
    ( initFaucet )
import Cardano.Launcher
                $ describe "with default port" $ do
                    PortCLI.specCommon @t
                    PortCLI.specWithDefaultPort @t
-
            (findPort >>= cardanoWalletServer (Just $ ListenOnPort defaultPort))
+
            (findPort >>= cardanoWalletServer (Just $ ListenOnPort $ getPort defaultPort))
                & beforeAll
                $ afterAll killServer
                $ describe "with specified port" $ do
    oneSecond :: Int
    oneSecond = 1 * 1000 * 1000 -- 1 second in microseconds

                      
-
    defaultPort :: Int
-
    defaultPort = 8090
+
    defaultPort :: Port "wallet"
+
    defaultPort = Port 8090

                      
    wait :: String -> IO () -> IO ()
    wait component action = do
        link cluster
        wait "cardano-node-simple" (waitForCluster nodeApiAddress)
        wait "cardano-http-bridge" (threadDelay oneSecond)
-
        (_, port, db, nl) <- cardanoWalletServer (Just ListenOnRandomPort) bridgePort
+
        (_, walletPort, db, nl) <-
+
            cardanoWalletServer (Just ListenOnRandomPort) bridgePort
        wait "cardano-wallet" (threadDelay oneSecond)
-
        let baseURL = mkBaseUrl port
+
        let baseURL = mkBaseUrl (getPort walletPort)
        manager <- (baseURL,) <$> newManager defaultManagerSettings
        faucet <- putStrLn "Creating money out of thin air..." *> initFaucet nl
        let estimator = mkFeeEstimator byronFeePolicy
        let cleanup = do
                cancel cluster
                hClose handle
                Sqlite.destroyDBLayer db
-
        return $ Context cleanup manager port (T.pack $ show bridgePort) faucet
+
        return $ Context cleanup manager walletPort (Port bridgePort) faucet
            estimator Proxy

                      
    killServer :: (HasType ThreadId s, HasType SqliteContext s) => s -> IO ()
        :: (network ~ HttpBridge 'Testnet)
        => Maybe Listen
        -> Int
-
        -> IO (ThreadId, Int, SqliteContext, NetworkLayer network IO)
+
        -> IO (ThreadId, Port "wallet", SqliteContext, NetworkLayer network IO)
    cardanoWalletServer mlisten bridgePort = do
        nl <- HttpBridge.newNetworkLayer bridgePort
        logConfig <- CM.empty
            let tl = HttpBridge.newTransactionLayer
            let bp = byronBlockchainParameters
            wallet <- newWalletLayer nullTracer bp db nl tl
-
            let listen = fromMaybe (ListenOnPort defaultPort) mlisten
+
            let listen = fromMaybe (ListenOnPort $ getPort defaultPort) mlisten
            Server.withListeningSocket listen $ \(port, socket) -> do
                let settings = Warp.defaultSettings
-
                        & setBeforeMainLoop (putMVar mvar port)
+
                        & setBeforeMainLoop (putMVar mvar (Port port))
                Server.start settings nullTracer socket wallet
        (thread,,ctx,nl) <$> takeMVar mvar

                      
{-# LANGUAGE AllowAmbiguousTypes #-}
+
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}

                      
import Prelude

                      
+
import Cardano.CLI
+
    ( Port (..) )
import Cardano.Wallet.Api.Types
    ( ApiWallet )
import Cardano.Wallet.Primitive.Types
                \prevents ongoing work to be integrated. So, disabling this \
                \while investigating the origin of the problem. \
                \See also: https://travis-ci.org/input-output-hk/cardano-wallet/jobs/565974586"
-
            port <- findPort -- Arbitrary but known.
+
            port <- Port @"wallet" <$> findPort -- Arbitrary but known.
            let baseUrl = "http://localhost:" <> toText port <> "/"
            ctx <- (port,) . (baseUrl,) <$> newManager defaultManagerSettings
            let args = ["launch", "--port", show port, "--state-dir", d]
{-# LANGUAGE AllowAmbiguousTypes #-}
+
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

                      

                      
import Prelude

                      
+
import Cardano.CLI
+
    ( Port )
import Control.Concurrent
    ( threadDelay )
import Control.Exception
    ( finally )
-
import Control.Monad
-
    ( forM_ )
import Data.Generics.Internal.VL.Lens
    ( (^.) )
+
import Data.Generics.Product.Typed
+
    ( typed )
import System.Command
    ( Exit (..), Stderr (..), Stdout (..) )
import System.Exit
    , cardanoWalletCLI
    , collectStreams
    , expectPathEventuallyExist
-
    , jormungandrBaseUrl
    , proc'
    , shouldContainT
    , shouldNotContainT
import Test.Utils.Ports
    ( findPort )

                      
-
import qualified Data.Text as T
-

                      
spec :: forall t. KnownCommand t => SpecWith (Context t)
spec = do
    describe "SERVER - cardano-wallet serve" $ do

                      
        it "SERVER - Stops gracefully on wrong network connection" $ \ctx -> do
            let faultyNetwork = "mainnet"
-
            let args = [ "serve", "--network", faultyNetwork
-
                       , "--node-port", T.unpack (ctx ^. jormungandrBaseUrl) ]
+
            let args =
+
                    [ "serve", "--network", faultyNetwork
+
                    , "--node-port", show (ctx ^. typed @(Port "node"))
+
                    ]
            (Exit c, Stdout out, Stderr err) <- cardanoWalletCLI @t args
            out `shouldContain` "The node backend is not running on the\
                \ \"" ++ faultyNetwork ++ "\" network. Please start the\

                      
    describe "DaedalusIPC" $ do
        let defaultArgs nodePort =
-
                [ commandName @t, "serve", "--node-port", T.unpack nodePort ]
-
        let tests =
-
                [ const ["--random-port"]
-
                , \fixedPort -> ["--port", fixedPort]
+
                [ commandName @t
+
                , "serve"
+
                , "--node-port"
+
                , show nodePort
                ]
-
        forM_ tests $ \args -> do
-
            let title = "should reply with the port when asked "
-
                    <> show (args "FIXED")
-
            it title $ \ctx -> do
-
                fixedPort <- findPort
-
                let filepath = "test/integration/js/mock-daedalus.js"
-
                let scriptArgs = defaultArgs (ctx ^. jormungandrBaseUrl)
-
                        ++ args (show fixedPort)
-
                (_, _, _, ph) <- createProcess (proc filepath scriptArgs)
-
                waitForProcess ph `shouldReturn` ExitSuccess
+

                      
+
        let filepath = "test/integration/js/mock-daedalus.js"
+

                      
+
        it "Should reply with the port --random" $ \ctx -> do
+
            let scriptArgs = defaultArgs (ctx ^. typed @(Port "node"))
+
                    ++ ["--random-port"]
+
            (_, _, _, ph) <- createProcess (proc filepath scriptArgs)
+
            waitForProcess ph `shouldReturn` ExitSuccess
+

                      
+
        it "Should reply with the port --random" $ \ctx -> do
+
            walletPort <- findPort
+
            let scriptArgs = defaultArgs (ctx ^. typed @(Port "node"))
+
                    ++ ["--port", show walletPort]
+
            (_, _, _, ph) <- createProcess (proc filepath scriptArgs)
+
            waitForProcess ph `shouldReturn` ExitSuccess

                      
    describe "LOGGING - cardano-wallet serve logging" $ do
        it "LOGGING - Launch can log --verbose" $ \_ -> do
+
{-# LANGUAGE DataKinds #-}
+

                      
-- |
-- Copyright: © 2018-2019 IOHK
-- License: Apache-2.0

                      
import Prelude

                      
+
import Cardano.CLI
+
    ( Port (..) )
import Cardano.Launcher
    ( Command (..), StdStream (..), launch )
import Cardano.Wallet.Jormungandr.Network
-- | Starts jormungandr on a random port using the integration tests config.
-- The data directory will be stored in a unique location under the system
-- temporary directory.
-
launchJormungandr :: StdStream -> IO (Async (), BaseUrl)
+
launchJormungandr :: StdStream -> IO (Async (), BaseUrl, Port "node")
launchJormungandr output = do
-
    (baseUrl, configYaml) <- setupConfig
+
    (baseUrl, port, configYaml) <- setupConfig
    let dir = "test/data/jormungandr"
    handle <- async $ void $ launch
        [ Command "jormungandr"
            ] (return ())
            output
        ]
-
    pure (handle, baseUrl)
+
    pure (handle, baseUrl, port)

                      
-- | Config for the test jormungandr.
data JormConfig = JormConfig
          ]
        ]

                      
-
setupConfig :: IO (BaseUrl, FilePath)
+
setupConfig :: IO (BaseUrl, Port "node", FilePath)
setupConfig = do
    [apiPort, nodePort] <- randomUnusedTCPPorts 2
    tmp <- getCanonicalTemporaryDirectory
        url = BaseUrl Http "localhost" apiPort "/api"
    encodeFile configYaml jormConfig
    createDirectory storageDir
-
    pure (url, configYaml)
+
    pure (url, Port apiPort, configYaml)
        :: (forall n. NetworkLayer n IO -> IO ())
        -> IO (Async (), NetworkLayer (Jormungandr 'Testnet) IO, BaseUrl)
    startNode wait = do
-
        (handle, baseUrl) <- launchJormungandr Inherit
+
        (handle, baseUrl, _) <- launchJormungandr Inherit
        nw <- Jormungandr.newNetworkLayer baseUrl
        wait nw $> (handle, nw, baseUrl)

                      
    ( setupTrace )
import Cardano.BM.Trace
    ( Trace, appendName )
+
import Cardano.CLI
+
    ( Port (..) )
import Cardano.Faucet
    ( block0H, initFaucet )
import Cardano.Launcher
import Cardano.Wallet.Jormungandr.Launch
    ( launchJormungandr )
import Cardano.Wallet.Jormungandr.Network
-
    ( BaseUrl (..), JormungandrLayer (..), baseUrlToText, mkJormungandrLayer )
+
    ( BaseUrl (..), JormungandrLayer (..), mkJormungandrLayer )
import Cardano.Wallet.Network
    ( NetworkLayer (..), defaultRetryPolicy, waitForConnection )
import Cardano.Wallet.Primitive.Fee
        describe "Ports CLI (default) tests [SERIAL]" $ do
            PortCLI.specCommon @t
            PortCLI.specWithDefaultPort @t
-
    let explicitPort = Just $ ListenOnPort defaultPort
+
    let explicitPort = Just $ ListenOnPort (getPort defaultPort)
    beforeAll (start explicitPort) $ afterAll _cleanup $ after tearDown $ do
        describe "Ports CLI (explicit) tests [SERIAL]" $ do
            PortCLI.specCommon @t
    start :: Maybe Listen -> IO (Context (Jormungandr 'Testnet))
    start listen = do
        logs <- openFile "/tmp/jormungandr" WriteMode -- fixme: non-portable
-
        (handle, jormungandrUrl) <- launchJormungandr (UseHandle logs)
-
        (handle', port, feePolicy, db) <- cardanoWalletServer jormungandrUrl listen
-
        let baseUrl = "http://localhost:" <> T.pack (show port) <> "/"
+
        (handle, jUrl, jPort) <- launchJormungandr (UseHandle logs)
+
        (handle', wPort, feePolicy, db) <- cardanoWalletServer jUrl listen
+
        let baseUrl = "http://localhost:" <> T.pack (show wPort) <> "/"
        manager <- (baseUrl,) <$> newManager defaultManagerSettings
        faucet <- initFaucet
        let estimator = mkFeeEstimator feePolicy
                hClose logs
                Sqlite.destroyDBLayer db
                threadDelay oneSecond
-
        let jmUrl = baseUrlToText jormungandrUrl
-
        return $ Context cleanup manager port jmUrl faucet estimator Proxy
+
        return $ Context cleanup manager wPort jPort faucet estimator Proxy

                      
-- | Initialize logging at the specified minimum 'Severity' level.
initTracer :: Severity -> Text -> IO (Trace IO Text)
    :: forall network. (network ~ Jormungandr 'Testnet)
    => BaseUrl
    -> Maybe Listen
-
    -> IO (Async (), Int, FeePolicy, SqliteContext)
+
    -> IO (Async (), Port "wallet", FeePolicy, SqliteContext)
cardanoWalletServer jormungandrUrl mlisten = do
    logConfig <- CM.empty
    tracer <- initTracer Info "serve"
    handle <- async $ do
        let tl = Jormungandr.newTransactionLayer block0H
        wallet <- newWalletLayer tracer bp db nl tl
-
        let listen = fromMaybe (ListenOnPort defaultPort) mlisten
+
        let listen = fromMaybe (ListenOnPort $ getPort defaultPort) mlisten
        Server.withListeningSocket listen $ \(port, socket) -> do
            let settings = Warp.defaultSettings
-
                    & setBeforeMainLoop (putMVar mvar port)
+
                    & setBeforeMainLoop (putMVar mvar (Port port))
            Server.start settings tracer socket wallet
    (handle, , getFeePolicy bp, sqlCtx) <$> takeMVar mvar

                      
oneSecond = 1000000

                      
-- | Default port for the wallet server
-
defaultPort :: Int
-
defaultPort = 8090
+
defaultPort :: Port "wallet"
+
defaultPort = Port 8090

                      
import Prelude

                      
+
import Cardano.CLI
+
    ( Port )
import Cardano.Faucet
    ( block0H )
import Cardano.Wallet.Api.Types
    ( Base (Base16, Base64), convertFromBase, convertToBase )
import Data.Generics.Internal.VL.Lens
    ( view, (^.) )
+
import Data.Generics.Product.Typed
+
    ( typed )
import Data.Proxy
    ( Proxy (..) )
import Data.Quantity
    , for
    , getFromResponse
    , getWalletEp
-
    , jormungandrBaseUrl
    , json
    , listAddresses
    , listAllTransactions
        let addrStr = encodeAddress (Proxy @t) (getApiT $ fst $ addr ^. #id)
        let amt = 1234

                      
-
        txBlob <- prepExternalTxViaJcli (ctx ^. jormungandrBaseUrl) addrStr amt
+
        txBlob <- prepExternalTxViaJcli (ctx ^. typed @(Port "node")) addrStr amt
        let payload = (NonJson . BL.fromStrict . toRawBytes Base16) txBlob
        let headers = Headers
                        [ ("Content-Type", "application/octet-stream")
            addr:_ <- listAddresses ctx w
            let addrStr = encodeAddress (Proxy @t) (getApiT $ fst $ addr ^. #id)

                      
-
            txBlob <- prepExternalTxViaJcli (ctx ^. jormungandrBaseUrl) addrStr 1
+
            txBlob <- prepExternalTxViaJcli (ctx ^. typed @(Port "node")) addrStr 1
            let payload = (NonJson . BL.fromStrict . toRawBytes Base16) txBlob
            let headers = Headers [ ("Content-Type", "application/octet-stream") ]

                      
            addr:_ <- listAddresses ctx w
            let addrStr = encodeAddress (Proxy @t) (getApiT $ fst $ addr ^. #id)

                      
-
            txBlob <- prepExternalTxViaJcli (ctx ^. jormungandrBaseUrl) addrStr 1
+
            txBlob <- prepExternalTxViaJcli (ctx ^. typed @(Port "node")) addrStr 1
            let payload = (NonJson . BL.fromStrict . toRawBytes Base16) txBlob

                      
            r <- request @ApiTxId ctx postExternalTxEp headers payload
{-# LANGUAGE AllowAmbiguousTypes #-}
+
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}

                      
import Prelude

                      
+
import Cardano.CLI
+
    ( Port (..) )
import Cardano.Wallet.Api.Types
    ( ApiWallet )
import Cardano.Wallet.Primitive.Types
                \prevents ongoing work to be integrated. So, disabling this \
                \while investigating the origin of the problem. \
                \See also: https://travis-ci.org/input-output-hk/cardano-wallet/jobs/565974586"
-
            port <- findPort -- Arbitrary but known.
+
            port <- Port @"wallet" <$> findPort -- Arbitrary but known.
            let baseUrl = "http://localhost:" <> toText port <> "/"
            ctx <- (port,) . (baseUrl,) <$> newManager defaultManagerSettings
            let args =
{-# LANGUAGE AllowAmbiguousTypes #-}
+
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

                      

                      
import Prelude

                      
+
import Cardano.CLI
+
    ( Port (..) )
import Cardano.Faucet
    ( block0HText )
import Control.Concurrent
    ( threadDelay )
import Control.Exception
    ( finally )
-
import Control.Monad
-
    ( forM_ )
import Data.Generics.Internal.VL.Lens
    ( (^.) )
+
import Data.Generics.Product.Typed
+
    ( typed )
import System.Exit
    ( ExitCode (..) )
import System.IO.Temp
    , KnownCommand (..)
    , collectStreams
    , expectPathEventuallyExist
-
    , jormungandrBaseUrl
    , proc'
    , shouldContainT
    , shouldNotContainT

                      
    describe "DaedalusIPC" $ do
        let defaultArgs nodePort =
-
                [ commandName @t , "serve", "--node-port", nodePort, "--genesis-hash", block0H ]
-
        let tests =
-
                [ const ["--random-port"]
-
                , \fixedPort -> ["--port", fixedPort]
+
                [ commandName @t
+
                , "serve"
+
                , "--node-port"
+
                , show nodePort
+
                , "--genesis-hash"
+
                , block0H
                ]
-
        forM_ tests $ \args -> do
-
            let title = "should reply with the port when asked "
-
                    <> show (args "FIXED")
-
            it title $ \ctx -> do
-
                fixedPort <- findPort
-
                let filepath = "test/integration/js/mock-daedalus.js"
-
                let urlPort = T.takeWhile (/= '/') . T.takeWhileEnd (/= ':')
-
                let nodePort = T.unpack $ urlPort $ ctx ^. jormungandrBaseUrl
-
                let scriptArgs = defaultArgs nodePort ++ args (show fixedPort)
-
                (_, _, _, ph) <- createProcess (proc filepath scriptArgs)
-
                waitForProcess ph `shouldReturn` ExitSuccess
+

                      
+
        let filepath = "test/integration/js/mock-daedalus.js"
+

                      
+
        it "Should reply with the port --random" $ \ctx -> do
+
            let scriptArgs = defaultArgs (ctx ^. typed @(Port "node"))
+
                    ++ ["--random-port"]
+
            (_, _, _, ph) <- createProcess (proc filepath scriptArgs)
+
            waitForProcess ph `shouldReturn` ExitSuccess
+

                      
+
        it "Should reply with the port --random" $ \ctx -> do
+
            walletPort <- findPort
+
            let scriptArgs = defaultArgs (ctx ^. typed @(Port "node"))
+
                    ++ ["--port", show walletPort]
+
            (_, _, _, ph) <- createProcess (proc filepath scriptArgs)
+
            waitForProcess ph `shouldReturn` ExitSuccess

                      
    describe "LOGGING - cardano-wallet serve logging" $ do
        it "LOGGING - Launch can log --verbose" $ \_ -> do

                      
import Prelude

                      
+
import Cardano.CLI
+
    ( Port )
import Cardano.Wallet.Api.Types
    ( ApiWallet, getApiT )
import Cardano.Wallet.Jormungandr.Binary
    ( Base (Base16, Base64), convertToBase )
import Data.Generics.Internal.VL.Lens
    ( (^.) )
+
import Data.Generics.Product.Typed
+
    ( typed )
import Data.Proxy
    ( Proxy (..) )
import Numeric.Natural
    , expectValidJSON
    , faucetAmt
    , getWalletViaCLI
-
    , jormungandrBaseUrl
    , listAddresses
    , postExternalTransactionViaCLI
    , prepExternalTxViaJcli
        let addrStr = encodeAddress (Proxy @t) (getApiT $ fst $ addr ^. #id)
        let amt = 4321

                      
-
        txBlob <- prepExternalTxViaJcli (ctx ^. jormungandrBaseUrl) addrStr amt
+
        txBlob <- prepExternalTxViaJcli (ctx ^. typed @(Port "node")) addrStr amt

                      
        (Exit code, Stdout out, Stderr err) <-
            postExternalTransactionViaCLI @t ctx [T.unpack txBlob]