-- SPDX-FileCopyrightText: 2021 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA

{-# OPTIONS_GHC -Wno-orphans #-}

-- | Interface to the @octez-client@ executable expressed in Haskell types.
module Morley.Client.TezosClient.Impl
  ( TezosClientError (..)

  -- * @octez-client@ api
  , signBytes
  , rememberContract
  , importKey
  , genKey
  , genFreshKey
  , revealKey
  , revealKeyUnlessRevealed
  , ResolveError(..)
  , Resolve(..)
  , resolveAddress
  , resolveAddressMaybe
  , getAlias
  , getAliasMaybe
  , getPublicKey
  , getSecretKey
  , getTezosClientConfig
  , calcTransferFee
  , calcOriginationFee
  , calcRevealFee
  , getKeyPassword
  , registerDelegate
  , getAliasesAndAddresses
  , resolveAddressWithAlias
  , resolveAddressWithAliasMaybe

    -- * For tests
  , lookupAliasCache
  ) where

import Data.Aeson (encode)
import Data.ByteArray (ScrubbedBytes)
import Data.ByteString.Lazy.Char8 qualified as C (unpack)
import Data.Constraint ((\\))
import Data.Text qualified as T
import Fmt (pretty, (+|), (|+))
import Text.Printf (printf)
import UnliftIO.IO (hGetEcho, hSetEcho)

import Lorentz.Value
import Morley.Client.App
import Morley.Client.Logging
import Morley.Client.RPC.Getters (getManagerKey)
import Morley.Client.TezosClient.Class qualified as Class
import Morley.Client.TezosClient.Config
import Morley.Client.TezosClient.Helpers
import Morley.Client.TezosClient.Parser
import Morley.Client.TezosClient.Resolve
import Morley.Client.TezosClient.Types
import Morley.Client.TezosClient.Types.Errors
import Morley.Client.TezosClient.Types.MorleyClientM
import Morley.Client.Types
import Morley.Client.Types.AliasesAndAddresses
import Morley.Client.Util (readScrubbedBytes)
import Morley.Micheline
import Morley.Michelson.Typed.Scope
import Morley.Tezos.Address
import Morley.Tezos.Address.Alias
import Morley.Tezos.Crypto
import Morley.Tezos.Crypto.Ed25519 qualified as Ed25519
import Morley.Util.Constrained
import Morley.Util.Peano
import Morley.Util.SizedList.Types

-- Note: if we try to sign with an unknown alias, @octez-client@ will
-- report a fatal error (assert failure) to stdout. It's bad. It's
-- reported in two issues: https://gitlab.com/tezos/tezos/-/issues/653
-- and https://gitlab.com/tezos/tezos/-/issues/813.
-- I (@gromak) currently think it's better to wait for it to be resolved upstream.
-- Currently we will throw 'TezosClientUnexpectedOutputFormat' error.
-- | Sign an arbtrary bytestring using @octez-client@.
-- Secret key of the address corresponding to give 'AddressOrAlias' must be known.
signBytes
  :: ImplicitAlias
  -> Maybe ScrubbedBytes
  -> ByteString
  -> MorleyClientM Signature
signBytes :: ImplicitAlias
-> Maybe ScrubbedBytes -> ByteString -> MorleyClientM Signature
signBytes ImplicitAlias
signerAlias Maybe ScrubbedBytes
mbPassword ByteString
opHash = do
  Text -> MorleyClientM ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Text
"Signing for " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ImplicitAlias -> Text
forall a b. (Buildable a, FromDoc b) => a -> b
pretty ImplicitAlias
signerAlias
  Text
output <- [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict
    [String
"sign", String
"bytes", ByteString -> String
forall a. CmdArg a => a -> String
toCmdArg ByteString
opHash, String
"for", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
signerAlias] CallMode
MockupMode Maybe ScrubbedBytes
mbPassword
  IO Signature -> MorleyClientM Signature
forall a. IO a -> MorleyClientM a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO case Text -> Text -> Maybe Text
T.stripPrefix Text
"Signature: " Text
output of
    Maybe Text
Nothing ->
      -- There is additional noise in the stdout in case key is password protected
      case Text -> Text -> Maybe Text
T.stripPrefix Text
"Enter password for encrypted key: Signature: " Text
output of
        Maybe Text
Nothing -> TezosClientError -> IO Signature
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> IO Signature)
-> TezosClientError -> IO Signature
forall a b. (a -> b) -> a -> b
$ Text -> TezosClientError
TezosClientUnexpectedSignatureOutput Text
output
        Just Text
signatureTxt -> Text -> IO Signature
forall (m :: * -> *). MonadCatch m => Text -> m Signature
txtToSignature Text
signatureTxt
    Just Text
signatureTxt -> Text -> IO Signature
forall (m :: * -> *). MonadCatch m => Text -> m Signature
txtToSignature Text
signatureTxt
  where
    txtToSignature :: MonadCatch m => Text -> m Signature
    txtToSignature :: forall (m :: * -> *). MonadCatch m => Text -> m Signature
txtToSignature Text
signatureTxt = (CryptoParseError -> m Signature)
-> (Signature -> m Signature)
-> Either CryptoParseError Signature
-> m Signature
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (TezosClientError -> m Signature
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> m Signature)
-> (CryptoParseError -> TezosClientError)
-> CryptoParseError
-> m Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> CryptoParseError -> TezosClientError
TezosClientCryptoParseError Text
signatureTxt) Signature -> m Signature
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either CryptoParseError Signature -> m Signature)
-> Either CryptoParseError Signature -> m Signature
forall a b. (a -> b) -> a -> b
$
      Text -> Either CryptoParseError Signature
parseSignature (Text -> Either CryptoParseError Signature)
-> (Text -> Text) -> Text -> Either CryptoParseError Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.strip (Text -> Either CryptoParseError Signature)
-> Text -> Either CryptoParseError Signature
forall a b. (a -> b) -> a -> b
$ Text
signatureTxt

-- | Generate a new secret key and save it with given alias.
-- If an address with given alias already exists, it will be returned
-- and no state will be changed.
genKey :: ImplicitAlias -> MorleyClientM ImplicitAddress
genKey :: ImplicitAlias -> MorleyClientM ImplicitAddress
genKey ImplicitAlias
name = do
  ImplicitAlias -> MorleyClientM (Maybe ImplicitAddress)
forall (kind :: AddressKind).
Alias kind -> MorleyClientM (Maybe (KindedAddress kind))
lookupAliasCache ImplicitAlias
name MorleyClientM (Maybe ImplicitAddress)
-> (Maybe ImplicitAddress -> MorleyClientM ImplicitAddress)
-> MorleyClientM ImplicitAddress
forall a b.
MorleyClientM a -> (a -> MorleyClientM b) -> MorleyClientM b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Just ImplicitAddress
addr -> ImplicitAddress -> MorleyClientM ImplicitAddress
forall a. a -> MorleyClientM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ImplicitAddress
addr
    Maybe ImplicitAddress
Nothing -> do
      let
        isAlreadyExistsError :: Text -> Bool
        -- We can do a bit better here using more complex parsing if necessary.
        isAlreadyExistsError :: Text -> Bool
isAlreadyExistsError = Text -> Text -> Bool
T.isInfixOf Text
"already exists."

        errHandler :: p -> Text -> f Bool
errHandler p
_ Text
errOut = Bool -> f Bool
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> Bool
isAlreadyExistsError Text
errOut)

      Text
_ <-
        (Text -> Text -> IO Bool)
-> [String]
-> CallMode
-> Maybe ScrubbedBytes
-> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
(Text -> Text -> IO Bool)
-> [String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClient Text -> Text -> IO Bool
forall {f :: * -> *} {p}. Applicative f => p -> Text -> f Bool
errHandler
        [String
"gen", String
"keys", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
name] CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing
      MorleyClientM ()
invalidateAliasCache
      ImplicitAlias -> MorleyClientM (ResolvedAddress ImplicitAlias)
forall addressOrAlias (m :: * -> *).
(HasTezosClient m, MonadThrow m, Resolve addressOrAlias) =>
addressOrAlias -> m (ResolvedAddress addressOrAlias)
resolveAddress ImplicitAlias
name

-- | Generate a new secret key and save it with given alias.
-- If an address with given alias already exists, it will be removed
-- and replaced with a fresh one.
genFreshKey :: ImplicitAlias -> MorleyClientM ImplicitAddress
genFreshKey :: ImplicitAlias -> MorleyClientM ImplicitAddress
genFreshKey ImplicitAlias
name = do
  let
    isNoAliasError :: Text -> Bool
    -- We can do a bit better here using more complex parsing if necessary.
    isNoAliasError :: Text -> Bool
isNoAliasError = Text -> Text -> Bool
T.isInfixOf Text
"no public key hash alias named"

    errHandler :: p -> Text -> f Bool
errHandler p
_ Text
errOutput = Bool -> f Bool
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> Bool
isNoAliasError Text
errOutput)

  Text
_ <-
    (Text -> Text -> IO Bool)
-> [String]
-> CallMode
-> Maybe ScrubbedBytes
-> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
(Text -> Text -> IO Bool)
-> [String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClient Text -> Text -> IO Bool
forall {f :: * -> *} {p}. Applicative f => p -> Text -> f Bool
errHandler
    [String
"forget", String
"address", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
name, String
"--force"] CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing
  [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict [String
"gen", String
"keys", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
name] CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing
  MorleyClientM ()
invalidateAliasCache
  ImplicitAlias -> MorleyClientM (ResolvedAddress ImplicitAlias)
forall addressOrAlias (m :: * -> *).
(HasTezosClient m, MonadThrow m, Resolve addressOrAlias) =>
addressOrAlias -> m (ResolvedAddress addressOrAlias)
resolveAddress ImplicitAlias
name

-- | Reveal public key corresponding to the given alias.
-- Fails if it's already revealed.
revealKey :: ImplicitAlias -> Maybe ScrubbedBytes -> MorleyClientM ()
revealKey :: ImplicitAlias -> Maybe ScrubbedBytes -> MorleyClientM ()
revealKey ImplicitAlias
alias Maybe ScrubbedBytes
mbPassword = do
  Text -> MorleyClientM ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Doc
"Revealing key for " Doc -> Doc -> Text
forall b. FromDoc b => Doc -> Doc -> b
+| ImplicitAlias
alias ImplicitAlias -> Doc -> Doc
forall a b. (Buildable a, FromDoc b) => a -> Doc -> b
|+ Doc
""
  let
    alreadyRevealed :: Text -> Bool
alreadyRevealed = Text -> Text -> Bool
T.isInfixOf Text
"previously revealed"
    revealedImplicitAccount :: Text -> Bool
revealedImplicitAccount = Text -> Text -> Bool
T.isInfixOf Text
"only implicit accounts can be revealed"
    emptyImplicitContract :: Text -> Bool
emptyImplicitContract = Text -> Text -> Bool
T.isInfixOf Text
"Empty implicit contract"
    errHandler :: Text -> Text -> IO Bool
errHandler Text
_ Text
errOut =
      Bool
False Bool -> IO () -> IO Bool
forall a b. a -> IO b -> IO a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ do
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Text -> Bool
alreadyRevealed Text
errOut) (TezosClientError -> IO ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (ImplicitAlias -> TezosClientError
AlreadyRevealed ImplicitAlias
alias))
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Text -> Bool
revealedImplicitAccount Text
errOut) (TezosClientError -> IO ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (ImplicitAlias -> TezosClientError
CantRevealContract ImplicitAlias
alias))
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Text -> Bool
emptyImplicitContract Text
errOut) (TezosClientError -> IO ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (ImplicitAlias -> TezosClientError
EmptyImplicitContract ImplicitAlias
alias))

  Text
_ <-
    (Text -> Text -> IO Bool)
-> [String]
-> CallMode
-> Maybe ScrubbedBytes
-> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
(Text -> Text -> IO Bool)
-> [String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClient Text -> Text -> IO Bool
errHandler
    [String
"reveal", String
"key", String
"for", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
alias] CallMode
ClientMode Maybe ScrubbedBytes
mbPassword

  Text -> MorleyClientM ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Doc
"Successfully revealed key for " Doc -> Doc -> Text
forall b. FromDoc b => Doc -> Doc -> b
+| ImplicitAlias
alias ImplicitAlias -> Doc -> Doc
forall a b. (Buildable a, FromDoc b) => a -> Doc -> b
|+ Doc
""

-- | Reveal key for implicit address if necessary.
revealKeyUnlessRevealed :: ImplicitAddressWithAlias -> Maybe ScrubbedBytes -> MorleyClientM ()
revealKeyUnlessRevealed :: ImplicitAddressWithAlias -> Maybe ScrubbedBytes -> MorleyClientM ()
revealKeyUnlessRevealed (AddressWithAlias ImplicitAddress
addr ImplicitAlias
alias) Maybe ScrubbedBytes
mbPassword = do
  Maybe PublicKey
mbManagerKey <- ImplicitAddress -> MorleyClientM (Maybe PublicKey)
forall (m :: * -> *).
HasTezosRpc m =>
ImplicitAddress -> m (Maybe PublicKey)
getManagerKey ImplicitAddress
addr
  case Maybe PublicKey
mbManagerKey of
    Maybe PublicKey
Nothing -> ImplicitAlias -> Maybe ScrubbedBytes -> MorleyClientM ()
revealKey ImplicitAlias
alias Maybe ScrubbedBytes
mbPassword
    Just PublicKey
_  -> Text -> MorleyClientM ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ ImplicitAlias
alias ImplicitAlias -> Doc -> Text
forall a b. (Buildable a, FromDoc b) => a -> Doc -> b
|+ Doc
" alias has already revealed key"

-- | Register alias as delegate
registerDelegate :: ImplicitAlias -> Maybe ScrubbedBytes -> MorleyClientM ()
registerDelegate :: ImplicitAlias -> Maybe ScrubbedBytes -> MorleyClientM ()
registerDelegate ImplicitAlias
alias Maybe ScrubbedBytes
mbPassword = do
  Text -> MorleyClientM ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Doc
"Registering " Doc -> Doc -> Text
forall b. FromDoc b => Doc -> Doc -> b
+| ImplicitAlias
alias ImplicitAlias -> Doc -> Doc
forall a b. (Buildable a, FromDoc b) => a -> Doc -> b
|+ Doc
" as delegate"
  let
    emptyImplicitContract :: Text -> Bool
emptyImplicitContract = Text -> Text -> Bool
T.isInfixOf Text
"Empty implicit contract"
    errHandler :: Text -> Text -> IO Bool
errHandler Text
_ Text
errOut =
      Bool
False Bool -> IO () -> IO Bool
forall a b. a -> IO b -> IO a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ do
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Text -> Bool
emptyImplicitContract Text
errOut) (TezosClientError -> IO ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (ImplicitAlias -> TezosClientError
EmptyImplicitContract ImplicitAlias
alias))

  Text
_ <-
    (Text -> Text -> IO Bool)
-> [String]
-> CallMode
-> Maybe ScrubbedBytes
-> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
(Text -> Text -> IO Bool)
-> [String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClient Text -> Text -> IO Bool
errHandler
    [String
"register", String
"key", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
alias, String
"as", String
"delegate"] CallMode
ClientMode Maybe ScrubbedBytes
mbPassword

  Text -> MorleyClientM ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Doc
"Successfully registered " Doc -> Doc -> Text
forall b. FromDoc b => Doc -> Doc -> b
+| ImplicitAlias
alias ImplicitAlias -> Doc -> Doc
forall a b. (Buildable a, FromDoc b) => a -> Doc -> b
|+ Doc
" as delegate"

-- | Call @octez-client@ to list known addresses or contracts
callListKnown :: String -> MorleyClientM Text
callListKnown :: String -> MorleyClientM Text
callListKnown String
objects =
  [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict [String
"list", String
"known", String
objects] CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing

-- | Return 'PublicKey' corresponding to given 'AddressOrAlias'.
getPublicKey
  :: ImplicitAlias
  -> MorleyClientM PublicKey
getPublicKey :: ImplicitAlias -> MorleyClientM PublicKey
getPublicKey ImplicitAlias
alias = do
  Text -> MorleyClientM ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Doc
"Getting " Doc -> Doc -> Text
forall b. FromDoc b => Doc -> Doc -> b
+| ImplicitAlias
alias ImplicitAlias -> Doc -> Doc
forall a b. (Buildable a, FromDoc b) => a -> Doc -> b
|+ Doc
" public key"
  Text
output <- [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict [String
"show", String
"address", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
alias] CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing
  IO PublicKey -> MorleyClientM PublicKey
forall a. IO a -> MorleyClientM a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO case Text -> [Text]
lines Text
output of
    Text
_ : [Text
rawPK] -> do
      Text
pkText <- IO Text -> (Text -> IO Text) -> Maybe Text -> IO Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
        (TezosClientError -> IO Text
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> IO Text) -> TezosClientError -> IO Text
forall a b. (a -> b) -> a -> b
$ Text -> TezosClientError
TezosClientUnexpectedOutputFormat Text
rawPK) Text -> IO Text
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        (Text -> Text -> Maybe Text
T.stripPrefix Text
"Public Key: " Text
rawPK)
      (CryptoParseError -> IO PublicKey)
-> (PublicKey -> IO PublicKey)
-> Either CryptoParseError PublicKey
-> IO PublicKey
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (TezosClientError -> IO PublicKey
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> IO PublicKey)
-> (CryptoParseError -> TezosClientError)
-> CryptoParseError
-> IO PublicKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> CryptoParseError -> TezosClientError
TezosClientCryptoParseError Text
pkText) PublicKey -> IO PublicKey
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either CryptoParseError PublicKey -> IO PublicKey)
-> Either CryptoParseError PublicKey -> IO PublicKey
forall a b. (a -> b) -> a -> b
$
        Text -> Either CryptoParseError PublicKey
parsePublicKey Text
pkText
    [Text]
_ -> TezosClientError -> IO PublicKey
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> IO PublicKey)
-> TezosClientError -> IO PublicKey
forall a b. (a -> b) -> a -> b
$ Text -> TezosClientError
TezosClientUnexpectedOutputFormat Text
output

-- | Return 'SecretKey' corresponding to given 'AddressOrAlias'.
getSecretKey
  :: ImplicitAlias
  -> MorleyClientM SecretKey
getSecretKey :: ImplicitAlias -> MorleyClientM SecretKey
getSecretKey ImplicitAlias
alias = do
  Text -> MorleyClientM ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Doc
"Getting " Doc -> Doc -> Text
forall b. FromDoc b => Doc -> Doc -> b
+| ImplicitAlias
alias ImplicitAlias -> Doc -> Doc
forall a b. (Buildable a, FromDoc b) => a -> Doc -> b
|+ Doc
" secret key"
  Text
output <- [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict [String
"show", String
"address", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
alias, String
"--show-secret"] CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing
  IO SecretKey -> MorleyClientM SecretKey
forall a. IO a -> MorleyClientM a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO case Text -> [Text]
lines Text
output of
    Text
_ : Text
_ : [Text
rawSK] -> do
      Text
skText <- IO Text -> (Text -> IO Text) -> Maybe Text -> IO Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
        (TezosClientError -> IO Text
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> IO Text) -> TezosClientError -> IO Text
forall a b. (a -> b) -> a -> b
$ Text -> TezosClientError
TezosClientUnexpectedOutputFormat Text
rawSK) Text -> IO Text
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        (Text -> Text -> Maybe Text
T.stripPrefix Text
"Secret Key: " Text
rawSK)
      (CryptoParseError -> IO SecretKey)
-> (SecretKey -> IO SecretKey)
-> Either CryptoParseError SecretKey
-> IO SecretKey
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (TezosClientError -> IO SecretKey
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> IO SecretKey)
-> (CryptoParseError -> TezosClientError)
-> CryptoParseError
-> IO SecretKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> CryptoParseError -> TezosClientError
TezosClientCryptoParseError Text
skText) SecretKey -> IO SecretKey
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either CryptoParseError SecretKey -> IO SecretKey)
-> Either CryptoParseError SecretKey -> IO SecretKey
forall a b. (a -> b) -> a -> b
$
        Text -> Either CryptoParseError SecretKey
parseSecretKey Text
skText
    [Text]
_ -> TezosClientError -> IO SecretKey
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> IO SecretKey)
-> TezosClientError -> IO SecretKey
forall a b. (a -> b) -> a -> b
$ Text -> TezosClientError
TezosClientUnexpectedOutputFormat Text
output

-- | Save a contract with given address and alias.
-- If @replaceExisting@ is @False@ and a contract with given alias
-- already exists, this function does nothing.
rememberContract
  :: AliasBehavior
  -> ContractAddress
  -> ContractAlias
  -> MorleyClientM ()
rememberContract :: AliasBehavior
-> ContractAddress -> ContractAlias -> MorleyClientM ()
rememberContract AliasBehavior
aliasBehavior ContractAddress
address ContractAlias
alias = do
  case AliasBehavior
aliasBehavior of
    AliasBehavior
DontSaveAlias ->
      Text -> MorleyClientM ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logInfo (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Doc
"Not saving " Doc -> Doc -> Text
forall b. FromDoc b => Doc -> Doc -> b
+| ContractAddress
address ContractAddress -> Doc -> Doc
forall a b. (Buildable a, FromDoc b) => a -> Doc -> b
|+ Doc
" as " Doc -> Doc -> Doc
forall b. FromDoc b => Doc -> Doc -> b
+| ContractAlias
alias ContractAlias -> Doc -> Doc
forall a b. (Buildable a, FromDoc b) => a -> Doc -> b
|+ Doc
" as requested"
    AliasBehavior
OverwriteDuplicateAlias -> do
      MorleyClientM Text -> MorleyClientM ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (MorleyClientM Text -> MorleyClientM ())
-> MorleyClientM Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict ([String]
args [String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<> [String
"--force"]) CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing
      ContractAlias -> ContractAddress -> MorleyClientM ()
forall (kind :: AddressKind).
Alias kind -> KindedAddress kind -> MorleyClientM ()
tryUpdateAliasCache ContractAlias
alias ContractAddress
address
    AliasBehavior
_ -> do
      ContractAlias -> MorleyClientM (Maybe ContractAddress)
forall (kind :: AddressKind).
Alias kind -> MorleyClientM (Maybe (KindedAddress kind))
lookupAliasCache ContractAlias
alias MorleyClientM (Maybe ContractAddress)
-> (Maybe ContractAddress -> MorleyClientM ()) -> MorleyClientM ()
forall a b.
MorleyClientM a -> (a -> MorleyClientM b) -> MorleyClientM b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Maybe ContractAddress
Nothing -> do
          let errHandler :: Text -> Text -> IO Bool
errHandler Text
_ Text
errOut
                | Text -> Bool
isAlreadyExistsError Text
errOut = case AliasBehavior
aliasBehavior of
                    AliasBehavior
KeepDuplicateAlias -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
                    AliasBehavior
ForbidDuplicateAlias -> TezosClientError -> IO Bool
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> IO Bool) -> TezosClientError -> IO Bool
forall a b. (a -> b) -> a -> b
$ Text -> TezosClientError
DuplicateAlias (Text -> TezosClientError) -> Text -> TezosClientError
forall a b. (a -> b) -> a -> b
$ ContractAlias -> Text
forall (kind :: AddressKind). Alias kind -> Text
unAlias ContractAlias
alias
                | Bool
otherwise = Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
          MorleyClientM Text -> MorleyClientM ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (MorleyClientM Text -> MorleyClientM ())
-> MorleyClientM Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ (Text -> Text -> IO Bool)
-> [String]
-> CallMode
-> Maybe ScrubbedBytes
-> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
(Text -> Text -> IO Bool)
-> [String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClient Text -> Text -> IO Bool
errHandler [String]
args CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing
          ContractAlias -> ContractAddress -> MorleyClientM ()
forall (kind :: AddressKind).
Alias kind -> KindedAddress kind -> MorleyClientM ()
tryUpdateAliasCache ContractAlias
alias ContractAddress
address
        Just{} -> case AliasBehavior
aliasBehavior of
          AliasBehavior
KeepDuplicateAlias -> MorleyClientM ()
forall (f :: * -> *). Applicative f => f ()
pass
          AliasBehavior
ForbidDuplicateAlias -> TezosClientError -> MorleyClientM ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> MorleyClientM ())
-> TezosClientError -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Text -> TezosClientError
DuplicateAlias (Text -> TezosClientError) -> Text -> TezosClientError
forall a b. (a -> b) -> a -> b
$ ContractAlias -> Text
forall (kind :: AddressKind). Alias kind -> Text
unAlias ContractAlias
alias
  where
    args :: [String]
args = [String
"remember", String
"contract", ContractAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ContractAlias
alias, ContractAddress -> String
forall a b. (Buildable a, FromDoc b) => a -> b
pretty ContractAddress
address]
    isAlreadyExistsError :: Text -> Bool
isAlreadyExistsError = Text -> Text -> Bool
T.isInfixOf Text
"already exists"

importKey
  :: Bool
  -> ImplicitAlias
  -> SecretKey
  -> MorleyClientM ImplicitAddressWithAlias
importKey :: Bool
-> ImplicitAlias
-> SecretKey
-> MorleyClientM ImplicitAddressWithAlias
importKey Bool
replaceExisting ImplicitAlias
name SecretKey
key = do
  let isAlreadyExistsError :: Text -> Bool
isAlreadyExistsError = Text -> Text -> Bool
T.isInfixOf Text
"already exists"
      errHandler :: Text -> Text -> IO Bool
errHandler Text
_ Text
errOut
        | Text -> Bool
isAlreadyExistsError Text
errOut = TezosClientError -> IO Bool
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> IO Bool) -> TezosClientError -> IO Bool
forall a b. (a -> b) -> a -> b
$ Text -> TezosClientError
DuplicateAlias (Text -> TezosClientError) -> Text -> TezosClientError
forall a b. (a -> b) -> a -> b
$ ImplicitAlias -> Text
forall (kind :: AddressKind). Alias kind -> Text
unAlias ImplicitAlias
name
        | Bool
otherwise = Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
      args :: [String]
args = [String
"import", String
"secret", String
"key", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
name, SecretKey -> String
forall a. CmdArg a => a -> String
toCmdArg SecretKey
key]
  MorleyClientM Text -> MorleyClientM ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (MorleyClientM Text -> MorleyClientM ())
-> MorleyClientM Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ (Text -> Text -> IO Bool)
-> [String]
-> CallMode
-> Maybe ScrubbedBytes
-> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
(Text -> Text -> IO Bool)
-> [String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClient Text -> Text -> IO Bool
errHandler
    (if Bool
replaceExisting then [String]
args [String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<> [String
"--force"] else [String]
args)
    CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing
  let addr :: ImplicitAddress
addr = PublicKey -> ImplicitAddress
mkKeyAddress (SecretKey -> PublicKey
toPublic SecretKey
key)
  ImplicitAlias -> ImplicitAddress -> MorleyClientM ()
forall (kind :: AddressKind).
Alias kind -> KindedAddress kind -> MorleyClientM ()
tryUpdateAliasCache ImplicitAlias
name ImplicitAddress
addr
  pure $ ImplicitAddress -> ImplicitAlias -> ImplicitAddressWithAlias
forall (kind :: AddressKind).
KindedAddress kind -> Alias kind -> AddressWithAlias kind
AddressWithAlias ImplicitAddress
addr ImplicitAlias
name

-- | Calc baker fee for transfer using @octez-client@.
calcTransferFee
  :: AddressOrAlias kind
  -> Maybe ScrubbedBytes
  -> TezosInt64
  -> [CalcTransferFeeData]
  -> MorleyClientM [TezosMutez]
calcTransferFee :: forall (kind :: AddressKind).
AddressOrAlias kind
-> Maybe ScrubbedBytes
-> TezosInt64
-> [CalcTransferFeeData]
-> MorleyClientM [TezosMutez]
calcTransferFee AddressOrAlias kind
from Maybe ScrubbedBytes
mbPassword TezosInt64
burnCap [CalcTransferFeeData]
transferFeeDatas = do
  Text
output <- [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict
    [ String
"multiple", String
"transfers", String
"from", AddressOrAlias kind -> String
forall a b. (Buildable a, FromDoc b) => a -> b
pretty AddressOrAlias kind
from, String
"using"
    , ByteString -> String
C.unpack (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ [CalcTransferFeeData] -> ByteString
forall a. ToJSON a => a -> ByteString
encode [CalcTransferFeeData]
transferFeeDatas, String
"--burn-cap", TezosInt64 -> String
showBurnCap TezosInt64
burnCap, String
"--dry-run"
    ] CallMode
ClientMode Maybe ScrubbedBytes
mbPassword
  Natural
-> (forall (n :: Natural).
    (KnownNat n, SingIPeano n) =>
    Proxy n -> MorleyClientM [TezosMutez])
-> MorleyClientM [TezosMutez]
forall r.
Natural
-> (forall (n :: Natural).
    (KnownNat n, SingIPeano n) =>
    Proxy n -> r)
-> r
withSomePeano ([CalcTransferFeeData] -> Natural
forall i a.
(Integral i, Container a,
 DefaultToInt (IsIntSubType Length i) i) =>
a -> i
length [CalcTransferFeeData]
transferFeeDatas) ((forall (n :: Natural).
  (KnownNat n, SingIPeano n) =>
  Proxy n -> MorleyClientM [TezosMutez])
 -> MorleyClientM [TezosMutez])
-> (forall (n :: Natural).
    (KnownNat n, SingIPeano n) =>
    Proxy n -> MorleyClientM [TezosMutez])
-> MorleyClientM [TezosMutez]
forall a b. (a -> b) -> a -> b
$
    \(Proxy n
_ :: Proxy n) -> SizedList' (ToPeano n) TezosMutez
-> [Element (SizedList' (ToPeano n) TezosMutez)]
SizedList' (ToPeano n) TezosMutez -> [TezosMutez]
forall t. Container t => t -> [Element t]
toList (SizedList' (ToPeano n) TezosMutez -> [TezosMutez])
-> MorleyClientM (SizedList' (ToPeano n) TezosMutez)
-> MorleyClientM [TezosMutez]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (n :: Natural).
SingIPeano n =>
Text -> MorleyClientM (SizedList n TezosMutez)
feeOutputParser @n Text
output

-- | Calc baker fee for origination using @octez-client@.
calcOriginationFee :: UntypedValScope st => CalcOriginationFeeData cp st -> MorleyClientM TezosMutez
calcOriginationFee :: forall (st :: T) (cp :: T).
UntypedValScope st =>
CalcOriginationFeeData cp st -> MorleyClientM TezosMutez
calcOriginationFee CalcOriginationFeeData{Maybe ScrubbedBytes
AddressOrAlias kind
Value st
Contract cp st
TezosInt64
TezosMutez
cofdFrom :: AddressOrAlias kind
cofdBalance :: TezosMutez
cofdMbFromPassword :: Maybe ScrubbedBytes
cofdContract :: Contract cp st
cofdStorage :: Value st
cofdBurnCap :: TezosInt64
cofdFrom :: ()
cofdBalance :: forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> TezosMutez
cofdMbFromPassword :: forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> Maybe ScrubbedBytes
cofdContract :: forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> Contract cp st
cofdStorage :: forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> Value st
cofdBurnCap :: forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> TezosInt64
..} = do
  Text
output <- [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict
    [ String
"originate", String
"contract", String
"-", String
"transferring"
    , TezosMutez -> String
showTez TezosMutez
cofdBalance
    , String
"from", AddressOrAlias kind -> String
forall a b. (Buildable a, FromDoc b) => a -> b
pretty AddressOrAlias kind
cofdFrom, String
"running"
    , Contract cp st -> String
forall a. CmdArg a => a -> String
toCmdArg Contract cp st
cofdContract, String
"--init"
    , Value st -> String
forall a. CmdArg a => a -> String
toCmdArg Value st
cofdStorage, String
"--burn-cap"
    , TezosInt64 -> String
showBurnCap TezosInt64
cofdBurnCap, String
"--dry-run"
    ] CallMode
ClientMode Maybe ScrubbedBytes
cofdMbFromPassword
  SizedList' ('S 'Z) TezosMutez
fees <- forall (n :: Natural).
SingIPeano n =>
Text -> MorleyClientM (SizedList n TezosMutez)
feeOutputParser @1 Text
output
  case SizedList' ('S 'Z) TezosMutez
fees of
    TezosMutez
singleFee :< SizedList' n1 TezosMutez
Nil -> TezosMutez -> MorleyClientM TezosMutez
forall a. a -> MorleyClientM a
forall (m :: * -> *) a. Monad m => a -> m a
return TezosMutez
singleFee

-- | Calc baker fee for revealing using @octez-client@.
--
-- Note that @octez-client@ does not support passing an address here,
-- at least at the moment of writing.
calcRevealFee :: ImplicitAlias -> Maybe ScrubbedBytes -> TezosInt64 -> MorleyClientM TezosMutez
calcRevealFee :: ImplicitAlias
-> Maybe ScrubbedBytes -> TezosInt64 -> MorleyClientM TezosMutez
calcRevealFee ImplicitAlias
alias Maybe ScrubbedBytes
mbPassword TezosInt64
burnCap = do
  Text
output <- [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict
    [ String
"reveal", String
"key", String
"for", ImplicitAlias -> String
forall a. CmdArg a => a -> String
toCmdArg ImplicitAlias
alias
    , String
"--burn-cap", TezosInt64 -> String
showBurnCap TezosInt64
burnCap
    , String
"--dry-run"
    ] CallMode
ClientMode Maybe ScrubbedBytes
mbPassword
  SizedList' ('S 'Z) TezosMutez
fees <- forall (n :: Natural).
SingIPeano n =>
Text -> MorleyClientM (SizedList n TezosMutez)
feeOutputParser @1 Text
output
  case SizedList' ('S 'Z) TezosMutez
fees of
    TezosMutez
singleFee :< SizedList' n1 TezosMutez
Nil -> TezosMutez -> MorleyClientM TezosMutez
forall a. a -> MorleyClientM a
forall (m :: * -> *) a. Monad m => a -> m a
return TezosMutez
singleFee

feeOutputParser :: forall n. (SingIPeano n) => Text -> MorleyClientM (SizedList n TezosMutez)
feeOutputParser :: forall (n :: Natural).
SingIPeano n =>
Text -> MorleyClientM (SizedList n TezosMutez)
feeOutputParser Text
output =
  case forall (n :: Natural).
SingIPeano n =>
Text -> Either FeeParserException (SizedList n TezosMutez)
parseBakerFeeFromOutput @n Text
output of
    Right SizedList n TezosMutez
fee -> SizedList n TezosMutez -> MorleyClientM (SizedList n TezosMutez)
forall a. a -> MorleyClientM a
forall (m :: * -> *) a. Monad m => a -> m a
return SizedList n TezosMutez
fee
    Left FeeParserException
err -> TezosClientError -> MorleyClientM (SizedList n TezosMutez)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> MorleyClientM (SizedList n TezosMutez))
-> TezosClientError -> MorleyClientM (SizedList n TezosMutez)
forall a b. (a -> b) -> a -> b
$ Text -> Text -> TezosClientError
TezosClientParseFeeError Text
output (Text -> TezosClientError) -> Text -> TezosClientError
forall a b. (a -> b) -> a -> b
$ FeeParserException -> Text
forall a b. (Buildable a, FromDoc b) => a -> b
pretty FeeParserException
err

showBurnCap :: TezosInt64 -> String
showBurnCap :: TezosInt64 -> String
showBurnCap TezosInt64
x = String -> Float -> String
forall r. PrintfType r => String -> r
printf String
"%.6f" (Float -> String) -> Float -> String
forall a b. (a -> b) -> a -> b
$ (forall a b.
(Integral a, RealFrac b, CheckIntSubType a Integer) =>
a -> b
fromIntegralToRealFrac @TezosInt64 @Float TezosInt64
x) Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
1000

showTez :: TezosMutez -> String
showTez :: TezosMutez -> String
showTez = Mutez -> String
forall a. CmdArg a => a -> String
toCmdArg (Mutez -> String) -> (TezosMutez -> Mutez) -> TezosMutez -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TezosMutez -> Mutez
unTezosMutez

-- | Get password for secret key associated with given address
-- in case this key is password-protected
getKeyPassword :: ImplicitAlias -> MorleyClientM (Maybe ScrubbedBytes)
getKeyPassword :: ImplicitAlias -> MorleyClientM (Maybe ScrubbedBytes)
getKeyPassword ImplicitAlias
alias = do
  Text
output <- [String] -> CallMode -> Maybe ScrubbedBytes -> MorleyClientM Text
forall env (m :: * -> *).
(WithClientLog env m, HasTezosClientEnv env, MonadIO m,
 MonadCatch m) =>
[String] -> CallMode -> Maybe ScrubbedBytes -> m Text
callTezosClientStrict [ String
"show", String
"address", ImplicitAlias -> String
forall a b. (Buildable a, FromDoc b) => a -> b
pretty ImplicitAlias
alias, String
"-S"] CallMode
MockupMode Maybe ScrubbedBytes
forall a. Maybe a
Nothing
  SecretKeyEncryption
encryptionType <-
    case Text
-> Either SecretKeyEncryptionParserException SecretKeyEncryption
parseSecretKeyEncryption Text
output of
      Right SecretKeyEncryption
t -> SecretKeyEncryption -> MorleyClientM SecretKeyEncryption
forall a. a -> MorleyClientM a
forall (m :: * -> *) a. Monad m => a -> m a
return SecretKeyEncryption
t
      Left SecretKeyEncryptionParserException
err -> TezosClientError -> MorleyClientM SecretKeyEncryption
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> MorleyClientM SecretKeyEncryption)
-> TezosClientError -> MorleyClientM SecretKeyEncryption
forall a b. (a -> b) -> a -> b
$ Text -> Text -> TezosClientError
TezosClientParseEncryptionTypeError Text
output (Text -> TezosClientError) -> Text -> TezosClientError
forall a b. (a -> b) -> a -> b
$ SecretKeyEncryptionParserException -> Text
forall a b. (Buildable a, FromDoc b) => a -> b
pretty SecretKeyEncryptionParserException
err
  case SecretKeyEncryption
encryptionType of
    SecretKeyEncryption
EncryptedKey -> do
      Text -> MorleyClientM ()
forall (m :: * -> *). MonadIO m => Text -> m ()
putTextLn (Text -> MorleyClientM ()) -> Text -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Text
"Please enter password for '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ImplicitAlias -> Text
forall a b. (Buildable a, FromDoc b) => a -> b
pretty ImplicitAlias
alias Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"':"
      ScrubbedBytes -> Maybe ScrubbedBytes
forall a. a -> Maybe a
Just (ScrubbedBytes -> Maybe ScrubbedBytes)
-> MorleyClientM ScrubbedBytes
-> MorleyClientM (Maybe ScrubbedBytes)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MorleyClientM ScrubbedBytes -> MorleyClientM ScrubbedBytes
forall (m :: * -> *) a. (MonadIO m, MonadMask m) => m a -> m a
withoutEcho MorleyClientM ScrubbedBytes
forall (m :: * -> *). MonadIO m => m ScrubbedBytes
readScrubbedBytes
    SecretKeyEncryption
_ -> Maybe ScrubbedBytes -> MorleyClientM (Maybe ScrubbedBytes)
forall a. a -> MorleyClientM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe ScrubbedBytes
forall a. Maybe a
Nothing

  where
    -- Hide entered password
    withoutEcho :: (MonadIO m, MonadMask m) => m a -> m a
    withoutEcho :: forall (m :: * -> *) a. (MonadIO m, MonadMask m) => m a -> m a
withoutEcho m a
action = do
      Bool
old <- Handle -> m Bool
forall (m :: * -> *). MonadIO m => Handle -> m Bool
hGetEcho Handle
stdin
      m () -> m () -> m a -> m a
forall (m :: * -> *) a b c. MonadMask m => m a -> m b -> m c -> m c
bracket_ (Handle -> Bool -> m ()
forall (m :: * -> *). MonadIO m => Handle -> Bool -> m ()
hSetEcho Handle
stdin Bool
False) (Handle -> Bool -> m ()
forall (m :: * -> *). MonadIO m => Handle -> Bool -> m ()
hSetEcho Handle
stdin Bool
old) m a
action

{- | Calls @octez-client list known contracts@ and returns
a list of @(alias, address)@ pairs.

Note that an alias can be ambiguous: it can refer to __both__ a contract and an implicit account.
When an alias "abc" is ambiguous, the list will contain two entries:

> ("abc", "KT1...")
> ("key:abc", "tz1...")
-}
getAliasesAndAddresses :: MorleyClientM AliasesAndAddresses
getAliasesAndAddresses :: MorleyClientM AliasesAndAddresses
getAliasesAndAddresses = do
  MorleyClientEnv
env <- MorleyClientM MorleyClientEnv
forall r (m :: * -> *). MonadReader r m => m r
ask
  let mv :: MVar (Maybe AliasesAndAddresses)
mv = MorleyClientEnv
env MorleyClientEnv
-> Getting
     (MVar (Maybe AliasesAndAddresses))
     MorleyClientEnv
     (MVar (Maybe AliasesAndAddresses))
-> MVar (Maybe AliasesAndAddresses)
forall s a. s -> Getting a s a -> a
^. (TezosClientEnv
 -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
-> MorleyClientEnv
-> Const (MVar (Maybe AliasesAndAddresses)) MorleyClientEnv
Lens' MorleyClientEnv TezosClientEnv
mceTezosClientL ((TezosClientEnv
  -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
 -> MorleyClientEnv
 -> Const (MVar (Maybe AliasesAndAddresses)) MorleyClientEnv)
-> ((MVar (Maybe AliasesAndAddresses)
     -> Const
          (MVar (Maybe AliasesAndAddresses))
          (MVar (Maybe AliasesAndAddresses)))
    -> TezosClientEnv
    -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
-> Getting
     (MVar (Maybe AliasesAndAddresses))
     MorleyClientEnv
     (MVar (Maybe AliasesAndAddresses))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MVar (Maybe AliasesAndAddresses)
 -> Const
      (MVar (Maybe AliasesAndAddresses))
      (MVar (Maybe AliasesAndAddresses)))
-> TezosClientEnv
-> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv
Lens' TezosClientEnv (MVar (Maybe AliasesAndAddresses))
tceAliasMapL
  MVar (Maybe AliasesAndAddresses)
-> StateT (Maybe AliasesAndAddresses) IO AliasesAndAddresses
-> MorleyClientM AliasesAndAddresses
forall (m :: * -> *) s a.
MonadIO m =>
MVar s -> StateT s IO a -> m a
updateMVar' MVar (Maybe AliasesAndAddresses)
mv (StateT (Maybe AliasesAndAddresses) IO AliasesAndAddresses
 -> MorleyClientM AliasesAndAddresses)
-> StateT (Maybe AliasesAndAddresses) IO AliasesAndAddresses
-> MorleyClientM AliasesAndAddresses
forall a b. (a -> b) -> a -> b
$ StateT (Maybe AliasesAndAddresses) IO (Maybe AliasesAndAddresses)
forall s (m :: * -> *). MonadState s m => m s
get StateT (Maybe AliasesAndAddresses) IO (Maybe AliasesAndAddresses)
-> (Maybe AliasesAndAddresses
    -> StateT (Maybe AliasesAndAddresses) IO AliasesAndAddresses)
-> StateT (Maybe AliasesAndAddresses) IO AliasesAndAddresses
forall a b.
StateT (Maybe AliasesAndAddresses) IO a
-> (a -> StateT (Maybe AliasesAndAddresses) IO b)
-> StateT (Maybe AliasesAndAddresses) IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Maybe AliasesAndAddresses
Nothing -> do
      AliasesAndAddresses
res <- IO AliasesAndAddresses
-> StateT (Maybe AliasesAndAddresses) IO AliasesAndAddresses
forall (m :: * -> *) a.
Monad m =>
m a -> StateT (Maybe AliasesAndAddresses) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO AliasesAndAddresses
 -> StateT (Maybe AliasesAndAddresses) IO AliasesAndAddresses)
-> IO AliasesAndAddresses
-> StateT (Maybe AliasesAndAddresses) IO AliasesAndAddresses
forall a b. (a -> b) -> a -> b
$ Text -> IO AliasesAndAddresses
parseOutput (Text -> IO AliasesAndAddresses)
-> IO Text -> IO AliasesAndAddresses
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< MorleyClientEnv -> MorleyClientM Text -> IO Text
forall a. MorleyClientEnv -> MorleyClientM a -> IO a
runMorleyClientM MorleyClientEnv
env (String -> MorleyClientM Text
callListKnown String
"contracts")
      Maybe AliasesAndAddresses
-> StateT (Maybe AliasesAndAddresses) IO ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (Maybe AliasesAndAddresses
 -> StateT (Maybe AliasesAndAddresses) IO ())
-> Maybe AliasesAndAddresses
-> StateT (Maybe AliasesAndAddresses) IO ()
forall a b. (a -> b) -> a -> b
$ AliasesAndAddresses -> Maybe AliasesAndAddresses
forall a. a -> Maybe a
Just AliasesAndAddresses
res
      pure AliasesAndAddresses
res
    Just AliasesAndAddresses
a -> AliasesAndAddresses
-> StateT (Maybe AliasesAndAddresses) IO AliasesAndAddresses
forall a. a -> StateT (Maybe AliasesAndAddresses) IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure AliasesAndAddresses
a
  where
    parseOutput :: Text -> IO AliasesAndAddresses
    parseOutput :: Text -> IO AliasesAndAddresses
parseOutput Text
out = [Constrained NullConstraint AddressWithAlias]
-> AliasesAndAddresses
mkAliasesAndAddresses ([Constrained NullConstraint AddressWithAlias]
 -> AliasesAndAddresses)
-> IO [Constrained NullConstraint AddressWithAlias]
-> IO AliasesAndAddresses
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text -> IO (Constrained NullConstraint AddressWithAlias))
-> [Text] -> IO [Constrained NullConstraint AddressWithAlias]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Text -> IO (Constrained NullConstraint AddressWithAlias)
parseLine (Text -> [Text]
lines Text
out)

    -- Note: each line has the format "<alias>: <address>"
    parseLine :: Text -> IO (Constrained NullConstraint AddressWithAlias)
    parseLine :: Text -> IO (Constrained NullConstraint AddressWithAlias)
parseLine Text
ln = do
      let (Text
aliasText', Text
addressText) = (Text -> Text) -> (Text, Text) -> (Text, Text)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Int -> Text -> Text
T.dropEnd Int
2) ((Text, Text) -> (Text, Text)) -> (Text, Text) -> (Text, Text)
forall a b. (a -> b) -> a -> b
$ HasCallStack => Text -> Text -> (Text, Text)
Text -> Text -> (Text, Text)
T.breakOnEnd Text
": " Text
ln
          -- This alias _might_ belong to both an implicit account and a contract,
          -- in which case it might be prefixed with "key".
          -- If so, we have to strip the prefix.
          aliasText :: Text
aliasText = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
aliasText' (Maybe Text -> Text) -> Maybe Text -> Text
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Maybe Text
T.stripPrefix Text
"key:" Text
aliasText'
      Constrained KindedAddress a
awaAddress <- Text
-> IO
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
parseL1Address Text
addressText
      let awaAlias :: Alias a
awaAlias = Text -> Alias a
forall (kind :: AddressKind).
(SingI kind, L1AddressKind kind) =>
Text -> Alias kind
mkAlias Text
aliasText (SingI a => Alias a) -> Dict (SingI a) -> Alias a
forall (c :: Constraint) e r. HasDict c e => (c => r) -> e -> r
\\ KindedAddress a -> Dict (SingI a)
forall (kind :: AddressKind).
KindedAddress kind -> Dict (SingI kind)
addressKindSanity KindedAddress a
awaAddress
      Constrained NullConstraint AddressWithAlias
-> IO (Constrained NullConstraint AddressWithAlias)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Constrained NullConstraint AddressWithAlias
 -> IO (Constrained NullConstraint AddressWithAlias))
-> (AddressWithAlias a
    -> Constrained NullConstraint AddressWithAlias)
-> AddressWithAlias a
-> IO (Constrained NullConstraint AddressWithAlias)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AddressWithAlias a -> Constrained NullConstraint AddressWithAlias
forall {k} (c :: k -> Constraint) (f :: k -> *) (a :: k).
c a =>
f a -> Constrained c f
Constrained (AddressWithAlias a
 -> IO (Constrained NullConstraint AddressWithAlias))
-> AddressWithAlias a
-> IO (Constrained NullConstraint AddressWithAlias)
forall a b. (a -> b) -> a -> b
$ AddressWithAlias{KindedAddress a
Alias a
awaAddress :: KindedAddress a
awaAlias :: Alias a
awaAddress :: KindedAddress a
awaAlias :: Alias a
..}

    parseL1Address :: Text -> IO L1Address
    parseL1Address :: Text
-> IO
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
parseL1Address Text
addrText
      = (ParseAddressError
 -> IO
      (Constrained
         (ConstrainAddressKind
            '[ 'AddressKindImplicit, 'AddressKindContract])
         KindedAddress))
-> (Constrained
      (ConstrainAddressKind
         '[ 'AddressKindImplicit, 'AddressKindContract])
      KindedAddress
    -> IO
         (Constrained
            (ConstrainAddressKind
               '[ 'AddressKindImplicit, 'AddressKindContract])
            KindedAddress))
-> Either
     ParseAddressError
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
-> IO
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (TezosClientError
-> IO
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError
 -> IO
      (Constrained
         (ConstrainAddressKind
            '[ 'AddressKindImplicit, 'AddressKindContract])
         KindedAddress))
-> (ParseAddressError -> TezosClientError)
-> ParseAddressError
-> IO
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ParseAddressError -> TezosClientError
TezosClientParseAddressError Text
addrText) Constrained
  (ConstrainAddressKind
     '[ 'AddressKindImplicit, 'AddressKindContract])
  KindedAddress
-> IO
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
      (Either
   ParseAddressError
   (Constrained
      (ConstrainAddressKind
         '[ 'AddressKindImplicit, 'AddressKindContract])
      KindedAddress)
 -> IO
      (Constrained
         (ConstrainAddressKind
            '[ 'AddressKindImplicit, 'AddressKindContract])
         KindedAddress))
-> (Text
    -> Either
         ParseAddressError
         (Constrained
            (ConstrainAddressKind
               '[ 'AddressKindImplicit, 'AddressKindContract])
            KindedAddress))
-> Text
-> IO
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text
-> Either
     ParseAddressError
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
forall (kinds :: [AddressKind]).
SingI kinds =>
Text -> Either ParseAddressError (ConstrainedAddress kinds)
parseConstrainedAddress (Text
 -> IO
      (Constrained
         (ConstrainAddressKind
            '[ 'AddressKindImplicit, 'AddressKindContract])
         KindedAddress))
-> Text
-> IO
     (Constrained
        (ConstrainAddressKind
           '[ 'AddressKindImplicit, 'AddressKindContract])
        KindedAddress)
forall a b. (a -> b) -> a -> b
$ Text
addrText

invalidateAliasCache :: MorleyClientM ()
invalidateAliasCache :: MorleyClientM ()
invalidateAliasCache = do
  MVar (Maybe AliasesAndAddresses)
mv <- Getting
  (MVar (Maybe AliasesAndAddresses))
  MorleyClientEnv
  (MVar (Maybe AliasesAndAddresses))
-> MorleyClientM (MVar (Maybe AliasesAndAddresses))
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (Getting
   (MVar (Maybe AliasesAndAddresses))
   MorleyClientEnv
   (MVar (Maybe AliasesAndAddresses))
 -> MorleyClientM (MVar (Maybe AliasesAndAddresses)))
-> Getting
     (MVar (Maybe AliasesAndAddresses))
     MorleyClientEnv
     (MVar (Maybe AliasesAndAddresses))
-> MorleyClientM (MVar (Maybe AliasesAndAddresses))
forall a b. (a -> b) -> a -> b
$ (TezosClientEnv
 -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
-> MorleyClientEnv
-> Const (MVar (Maybe AliasesAndAddresses)) MorleyClientEnv
forall env. HasTezosClientEnv env => Lens' env TezosClientEnv
Lens' MorleyClientEnv TezosClientEnv
tezosClientEnvL ((TezosClientEnv
  -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
 -> MorleyClientEnv
 -> Const (MVar (Maybe AliasesAndAddresses)) MorleyClientEnv)
-> ((MVar (Maybe AliasesAndAddresses)
     -> Const
          (MVar (Maybe AliasesAndAddresses))
          (MVar (Maybe AliasesAndAddresses)))
    -> TezosClientEnv
    -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
-> Getting
     (MVar (Maybe AliasesAndAddresses))
     MorleyClientEnv
     (MVar (Maybe AliasesAndAddresses))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MVar (Maybe AliasesAndAddresses)
 -> Const
      (MVar (Maybe AliasesAndAddresses))
      (MVar (Maybe AliasesAndAddresses)))
-> TezosClientEnv
-> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv
Lens' TezosClientEnv (MVar (Maybe AliasesAndAddresses))
tceAliasMapL
  MVar (Maybe AliasesAndAddresses)
-> StateT (Maybe AliasesAndAddresses) IO () -> MorleyClientM ()
forall (m :: * -> *) s a.
MonadIO m =>
MVar s -> StateT s IO a -> m a
updateMVar' MVar (Maybe AliasesAndAddresses)
mv (StateT (Maybe AliasesAndAddresses) IO () -> MorleyClientM ())
-> StateT (Maybe AliasesAndAddresses) IO () -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ Maybe AliasesAndAddresses
-> StateT (Maybe AliasesAndAddresses) IO ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put Maybe AliasesAndAddresses
forall a. Maybe a
Nothing

tryUpdateAliasCache :: Alias kind -> KindedAddress kind -> MorleyClientM ()
tryUpdateAliasCache :: forall (kind :: AddressKind).
Alias kind -> KindedAddress kind -> MorleyClientM ()
tryUpdateAliasCache Alias kind
alias KindedAddress kind
addr = do
  MVar (Maybe AliasesAndAddresses)
mv <- Getting
  (MVar (Maybe AliasesAndAddresses))
  MorleyClientEnv
  (MVar (Maybe AliasesAndAddresses))
-> MorleyClientM (MVar (Maybe AliasesAndAddresses))
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (Getting
   (MVar (Maybe AliasesAndAddresses))
   MorleyClientEnv
   (MVar (Maybe AliasesAndAddresses))
 -> MorleyClientM (MVar (Maybe AliasesAndAddresses)))
-> Getting
     (MVar (Maybe AliasesAndAddresses))
     MorleyClientEnv
     (MVar (Maybe AliasesAndAddresses))
-> MorleyClientM (MVar (Maybe AliasesAndAddresses))
forall a b. (a -> b) -> a -> b
$ (TezosClientEnv
 -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
-> MorleyClientEnv
-> Const (MVar (Maybe AliasesAndAddresses)) MorleyClientEnv
forall env. HasTezosClientEnv env => Lens' env TezosClientEnv
Lens' MorleyClientEnv TezosClientEnv
tezosClientEnvL ((TezosClientEnv
  -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
 -> MorleyClientEnv
 -> Const (MVar (Maybe AliasesAndAddresses)) MorleyClientEnv)
-> ((MVar (Maybe AliasesAndAddresses)
     -> Const
          (MVar (Maybe AliasesAndAddresses))
          (MVar (Maybe AliasesAndAddresses)))
    -> TezosClientEnv
    -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
-> Getting
     (MVar (Maybe AliasesAndAddresses))
     MorleyClientEnv
     (MVar (Maybe AliasesAndAddresses))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MVar (Maybe AliasesAndAddresses)
 -> Const
      (MVar (Maybe AliasesAndAddresses))
      (MVar (Maybe AliasesAndAddresses)))
-> TezosClientEnv
-> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv
Lens' TezosClientEnv (MVar (Maybe AliasesAndAddresses))
tceAliasMapL
  MVar (Maybe AliasesAndAddresses)
-> StateT (Maybe AliasesAndAddresses) IO () -> MorleyClientM ()
forall (m :: * -> *) s a.
MonadIO m =>
MVar s -> StateT s IO a -> m a
updateMVar' MVar (Maybe AliasesAndAddresses)
mv (StateT (Maybe AliasesAndAddresses) IO () -> MorleyClientM ())
-> StateT (Maybe AliasesAndAddresses) IO () -> MorleyClientM ()
forall a b. (a -> b) -> a -> b
$ (Maybe AliasesAndAddresses -> Maybe AliasesAndAddresses)
-> StateT (Maybe AliasesAndAddresses) IO ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Maybe AliasesAndAddresses -> Maybe AliasesAndAddresses)
 -> StateT (Maybe AliasesAndAddresses) IO ())
-> (Maybe AliasesAndAddresses -> Maybe AliasesAndAddresses)
-> StateT (Maybe AliasesAndAddresses) IO ()
forall a b. (a -> b) -> a -> b
$ (AliasesAndAddresses -> AliasesAndAddresses)
-> Maybe AliasesAndAddresses -> Maybe AliasesAndAddresses
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((AliasesAndAddresses -> AliasesAndAddresses)
 -> Maybe AliasesAndAddresses -> Maybe AliasesAndAddresses)
-> (AliasesAndAddresses -> AliasesAndAddresses)
-> Maybe AliasesAndAddresses
-> Maybe AliasesAndAddresses
forall a b. (a -> b) -> a -> b
$ Alias kind
-> KindedAddress kind -> AliasesAndAddresses -> AliasesAndAddresses
forall (kind :: AddressKind).
Alias kind
-> KindedAddress kind -> AliasesAndAddresses -> AliasesAndAddresses
insertAliasAndAddress Alias kind
alias KindedAddress kind
addr

lookupAliasCache :: Alias kind -> MorleyClientM (Maybe (KindedAddress kind))
lookupAliasCache :: forall (kind :: AddressKind).
Alias kind -> MorleyClientM (Maybe (KindedAddress kind))
lookupAliasCache Alias kind
alias = do
  MVar (Maybe AliasesAndAddresses)
mv <- Getting
  (MVar (Maybe AliasesAndAddresses))
  MorleyClientEnv
  (MVar (Maybe AliasesAndAddresses))
-> MorleyClientM (MVar (Maybe AliasesAndAddresses))
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (Getting
   (MVar (Maybe AliasesAndAddresses))
   MorleyClientEnv
   (MVar (Maybe AliasesAndAddresses))
 -> MorleyClientM (MVar (Maybe AliasesAndAddresses)))
-> Getting
     (MVar (Maybe AliasesAndAddresses))
     MorleyClientEnv
     (MVar (Maybe AliasesAndAddresses))
-> MorleyClientM (MVar (Maybe AliasesAndAddresses))
forall a b. (a -> b) -> a -> b
$ (TezosClientEnv
 -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
-> MorleyClientEnv
-> Const (MVar (Maybe AliasesAndAddresses)) MorleyClientEnv
forall env. HasTezosClientEnv env => Lens' env TezosClientEnv
Lens' MorleyClientEnv TezosClientEnv
tezosClientEnvL ((TezosClientEnv
  -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
 -> MorleyClientEnv
 -> Const (MVar (Maybe AliasesAndAddresses)) MorleyClientEnv)
-> ((MVar (Maybe AliasesAndAddresses)
     -> Const
          (MVar (Maybe AliasesAndAddresses))
          (MVar (Maybe AliasesAndAddresses)))
    -> TezosClientEnv
    -> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv)
-> Getting
     (MVar (Maybe AliasesAndAddresses))
     MorleyClientEnv
     (MVar (Maybe AliasesAndAddresses))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MVar (Maybe AliasesAndAddresses)
 -> Const
      (MVar (Maybe AliasesAndAddresses))
      (MVar (Maybe AliasesAndAddresses)))
-> TezosClientEnv
-> Const (MVar (Maybe AliasesAndAddresses)) TezosClientEnv
Lens' TezosClientEnv (MVar (Maybe AliasesAndAddresses))
tceAliasMapL
  (Alias kind -> AliasesAndAddresses -> Maybe (KindedAddress kind)
forall (kind :: AddressKind).
Alias kind -> AliasesAndAddresses -> Maybe (KindedAddress kind)
lookupAddr Alias kind
alias (AliasesAndAddresses -> Maybe (KindedAddress kind))
-> Maybe AliasesAndAddresses -> Maybe (KindedAddress kind)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) (Maybe AliasesAndAddresses -> Maybe (KindedAddress kind))
-> MorleyClientM (Maybe AliasesAndAddresses)
-> MorleyClientM (Maybe (KindedAddress kind))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar (Maybe AliasesAndAddresses)
-> MorleyClientM (Maybe AliasesAndAddresses)
forall (m :: * -> *) a. MonadIO m => MVar a -> m a
readMVar MVar (Maybe AliasesAndAddresses)
mv

instance Class.HasTezosClient MorleyClientM where
  signBytes :: ImplicitAddressWithAlias
-> Maybe ScrubbedBytes -> ByteString -> MorleyClientM Signature
signBytes (AddressWithAlias ImplicitAddress
_ ImplicitAlias
senderAlias) Maybe ScrubbedBytes
mbPassword ByteString
opHash = MorleyClientM Signature -> MorleyClientM Signature
forall (m :: * -> *) a.
(MonadUnliftIO m, MonadThrow m) =>
m a -> m a
retryOnceOnTimeout (MorleyClientM Signature -> MorleyClientM Signature)
-> MorleyClientM Signature -> MorleyClientM Signature
forall a b. (a -> b) -> a -> b
$ do
    MorleyClientEnv
env <- MorleyClientM MorleyClientEnv
forall r (m :: * -> *). MonadReader r m => m r
ask
    case MorleyClientEnv -> Maybe SecretKey
mceSecretKey MorleyClientEnv
env of
      Just SecretKey
sk -> Signature -> MorleyClientM Signature
forall a. a -> MorleyClientM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Signature -> MorleyClientM Signature)
-> (Signature -> Signature) -> Signature -> MorleyClientM Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signature -> Signature
SignatureEd25519 (Signature -> MorleyClientM Signature)
-> Signature -> MorleyClientM Signature
forall a b. (a -> b) -> a -> b
$ SecretKey -> ByteString -> Signature
Ed25519.sign SecretKey
sk ByteString
opHash
      Maybe SecretKey
Nothing -> ImplicitAlias
-> Maybe ScrubbedBytes -> ByteString -> MorleyClientM Signature
signBytes ImplicitAlias
senderAlias Maybe ScrubbedBytes
mbPassword ByteString
opHash
  rememberContract :: AliasBehavior
-> ContractAddress -> ContractAlias -> MorleyClientM ()
rememberContract = MorleyClientM () -> MorleyClientM ()
forall (m :: * -> *) a.
(MonadUnliftIO m, MonadThrow m) =>
m a -> m a
failOnTimeout (MorleyClientM () -> MorleyClientM ())
-> (AliasBehavior
    -> ContractAddress -> ContractAlias -> MorleyClientM ())
-> AliasBehavior
-> ContractAddress
-> ContractAlias
-> MorleyClientM ()
forall a b c. SuperComposition a b c => a -> b -> c
... AliasBehavior
-> ContractAddress -> ContractAlias -> MorleyClientM ()
rememberContract
  getAliasesAndAddresses :: MorleyClientM AliasesAndAddresses
getAliasesAndAddresses = MorleyClientM AliasesAndAddresses
-> MorleyClientM AliasesAndAddresses
forall (m :: * -> *) a.
(MonadUnliftIO m, MonadThrow m) =>
m a -> m a
retryOnceOnTimeout (MorleyClientM AliasesAndAddresses
 -> MorleyClientM AliasesAndAddresses)
-> MorleyClientM AliasesAndAddresses
-> MorleyClientM AliasesAndAddresses
forall a b c. SuperComposition a b c => a -> b -> c
... MorleyClientM AliasesAndAddresses
getAliasesAndAddresses
  genKey :: ImplicitAlias -> MorleyClientM ImplicitAddressWithAlias
genKey ImplicitAlias
alias = (ImplicitAddress -> ImplicitAlias -> ImplicitAddressWithAlias)
-> ImplicitAlias -> ImplicitAddress -> ImplicitAddressWithAlias
forall a b c. (a -> b -> c) -> b -> a -> c
flip ImplicitAddress -> ImplicitAlias -> ImplicitAddressWithAlias
forall (kind :: AddressKind).
KindedAddress kind -> Alias kind -> AddressWithAlias kind
AddressWithAlias ImplicitAlias
alias (ImplicitAddress -> ImplicitAddressWithAlias)
-> MorleyClientM ImplicitAddress
-> MorleyClientM ImplicitAddressWithAlias
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ImplicitAlias -> MorleyClientM ImplicitAddress
genKey ImplicitAlias
alias
  genFreshKey :: ImplicitAlias -> MorleyClientM ImplicitAddressWithAlias
genFreshKey ImplicitAlias
alias = (ImplicitAddress -> ImplicitAlias -> ImplicitAddressWithAlias)
-> ImplicitAlias -> ImplicitAddress -> ImplicitAddressWithAlias
forall a b c. (a -> b -> c) -> b -> a -> c
flip ImplicitAddress -> ImplicitAlias -> ImplicitAddressWithAlias
forall (kind :: AddressKind).
KindedAddress kind -> Alias kind -> AddressWithAlias kind
AddressWithAlias ImplicitAlias
alias (ImplicitAddress -> ImplicitAddressWithAlias)
-> MorleyClientM ImplicitAddress
-> MorleyClientM ImplicitAddressWithAlias
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ImplicitAlias -> MorleyClientM ImplicitAddress
genFreshKey ImplicitAlias
alias
  getKeyPassword :: ImplicitAddressWithAlias -> MorleyClientM (Maybe ScrubbedBytes)
getKeyPassword (AddressWithAlias ImplicitAddress
_ ImplicitAlias
alias) = MorleyClientM (Maybe ScrubbedBytes)
-> MorleyClientM (Maybe ScrubbedBytes)
forall (m :: * -> *) a.
(MonadUnliftIO m, MonadThrow m) =>
m a -> m a
retryOnceOnTimeout (MorleyClientM (Maybe ScrubbedBytes)
 -> MorleyClientM (Maybe ScrubbedBytes))
-> MorleyClientM (Maybe ScrubbedBytes)
-> MorleyClientM (Maybe ScrubbedBytes)
forall a b. (a -> b) -> a -> b
$ ImplicitAlias -> MorleyClientM (Maybe ScrubbedBytes)
getKeyPassword ImplicitAlias
alias
  getPublicKey :: ImplicitAddressWithAlias -> MorleyClientM PublicKey
getPublicKey (AddressWithAlias ImplicitAddress
_ ImplicitAlias
alias) = ImplicitAlias -> MorleyClientM PublicKey
getPublicKey ImplicitAlias
alias