cardano-addresses-4.0.0: lib/Command/Address/Bootstrap.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_HADDOCK hide #-}
{-# OPTIONS_GHC -fno-warn-deprecations #-}
-- |
-- Copyright: 2020 Input Output (Hong Kong) Ltd., 2021-2022 Input Output Global Inc. (IOG), 2023-2025 Intersect
-- License: Apache-2.0
module Command.Address.Bootstrap
( Cmd
, mod
, run
) where
import Prelude hiding
( mod )
import Cardano.Address
( AddressDiscrimination (..), NetworkDiscriminant, base58 )
import Cardano.Address.Derivation
( XPub, coerceWholeDomainIndex )
import Cardano.Address.Style.Byron
( Byron )
import Data.Text
( Text )
import Options.Applicative
( CommandFields
, Mod
, command
, footerDoc
, header
, helper
, info
, optional
, progDesc
)
import Options.Applicative.Derivation
( DerivationPath, castDerivationPath, derivationPathArg, xpubOpt )
import Options.Applicative.Discrimination
( NetworkTag (..), networkTagOpt )
import Options.Applicative.Help.Pretty
( Doc, annotate, bold, indent, pretty, vsep )
import Options.Applicative.Style
( Style (..) )
import System.IO
( stdin, stdout )
import System.IO.Extra
( hGetXPub, progName )
import qualified Cardano.Address.Style.Byron as Byron
import qualified Cardano.Address.Style.Icarus as Icarus
import qualified Cardano.Codec.Bech32.Prefixes as CIP5
import qualified Data.ByteString.Char8 as B8
import qualified Data.Text.Encoding as T
data Cmd = Cmd
{ rootXPub :: Maybe XPub
, networkTag :: NetworkTag
, derivationPath :: Maybe DerivationPath
} deriving (Show)
mod :: (Cmd -> parent) -> Mod CommandFields parent
mod liftCmd = command "bootstrap" $
info (helper <*> fmap liftCmd parser) $ mempty
<> progDesc "Create a bootstrap address"
<> header "Those addresses, now deprecated, were used during the Byron era."
<> footerDoc (Just $ vsep
[ prettyText "Example:"
, indent 2 $ annotate bold $ pretty $ "$ "<>progName<>" recovery-phrase generate --size 12 \\"
, indent 4 $ annotate bold $ pretty $ "| "<>progName<>" key from-recovery-phrase Byron > root.prv"
, indent 2 $ prettyText ""
, indent 2 $ annotate bold $ prettyText "$ cat root.prv \\"
, indent 4 $ annotate bold $ pretty $ "| "<>progName<>" key child 14H/42H | tee addr.prv \\"
, indent 4 $ annotate bold $ pretty $ "| "<>progName<>" key public --with-chain-code \\"
, indent 4 $ annotate bold $ pretty $ "| "<>progName<>" address bootstrap --root $(cat root.prv | "<>progName<>" key public --with-chain-code) \\"
, indent 8 $ annotate bold $ prettyText "--network-tag preview 14H/42H"
, indent 2 $ prettyText "KjgoiXJS2coBYYTM69pafiau6bbGqKrzbFiRzahpWsPvit48YNiHocPpB7VJ..."
])
where
parser = Cmd
<$> optional (xpubOpt [CIP5.root_xvk] "root" "A root public key. Needed for Byron addresses only.")
<*> networkTagOpt Byron
<*> optional derivationPathArg
prettyText :: Text -> Doc
prettyText = pretty
run :: Cmd -> IO ()
run Cmd{networkTag,rootXPub,derivationPath} = do
(_hrp, xpub) <- hGetXPub stdin [CIP5.addr_xvk]
addr <- case derivationPath of
Nothing ->
pure $ Icarus.paymentAddress discriminant (Icarus.liftXPub xpub)
Just untypedPath -> do
root <- maybe
(fail "A root public key must be provided when --path is provided") pure rootXPub
case castDerivationPath untypedPath of
[acctIx, addrIx] -> do
let path = (acctIx, coerceWholeDomainIndex addrIx)
xkey = Byron.liftXPub root path xpub
pure $ Byron.paymentAddress discriminant xkey
_ -> do
fail "Byron derivation path must describe 2 levels (e.g. 0H/0H)"
B8.hPutStr stdout $ T.encodeUtf8 $ base58 addr
where
discriminant :: NetworkDiscriminant Byron -- Or Icarus, same.
discriminant
| networkTag == snd Byron.byronMainnet =
Byron.byronMainnet
| otherwise =
(RequiresNetworkTag, networkTag)