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

-- | Types used for interaction with @octez-client@.

module Morley.Client.TezosClient.Types
  ( CmdArg (..)
  -- , addressResolved
  , CalcOriginationFeeData (..)
  , CalcTransferFeeData (..)
  , TezosClientConfig (..)
  , TezosClientEnv (..)
  , HasTezosClientEnv (..)
  , SecretKeyEncryption (..)

  -- * Lens
  , tceEndpointUrlL
  , tceTezosClientPathL
  , tceMbTezosClientDataDirL
  ) where

import Data.Aeson (FromJSON(..), KeyValue(..), ToJSON(..), object, withObject, (.:))
import Data.ByteArray (ScrubbedBytes)
import Data.Fixed (E6, Fixed(..))
import Fmt (Buildable(..), pretty)
import Morley.Util.Lens (makeLensesWith, postfixLFields)
import Servant.Client (BaseUrl(..), showBaseUrl)
import Text.Hex (encodeHex)

-- import Lorentz (ToAddress, toAddress)
import Morley.Client.RPC.Types (OperationHash)
import Morley.Client.Util
import Morley.Micheline
import Morley.Michelson.Printer
import Morley.Michelson.Typed (Contract, EpName, Value)
import Morley.Michelson.Typed qualified as T
import Morley.Tezos.Address
import Morley.Tezos.Address.Alias (AddressOrAlias(..), Alias)
import Morley.Tezos.Core
import Morley.Tezos.Crypto

-- | An object that can be put as argument to a @octez-client@ command-line call.
class CmdArg a where
  -- | Render an object as a command-line argument.
  toCmdArg :: a -> String
  default toCmdArg :: Buildable a => a -> String
  toCmdArg = a -> String
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty

instance CmdArg Text where

instance CmdArg LText where

instance CmdArg Word16 where

instance CmdArg SecretKey where
  toCmdArg :: SecretKey -> String
toCmdArg = Text -> String
forall a. CmdArg a => a -> String
toCmdArg (Text -> String) -> (SecretKey -> Text) -> SecretKey -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecretKey -> Text
formatSecretKey

instance CmdArg (KindedAddress kind) where

instance CmdArg Address where

instance CmdArg ByteString where
  toCmdArg :: ByteString -> String
toCmdArg = Text -> String
forall a. CmdArg a => a -> String
toCmdArg (Text -> String) -> (ByteString -> Text) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
"0x" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>) (Text -> Text) -> (ByteString -> Text) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
encodeHex

instance CmdArg EpName where
  toCmdArg :: EpName -> String
toCmdArg = Text -> String
forall a. CmdArg a => a -> String
toCmdArg (Text -> String) -> (EpName -> Text) -> EpName -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EpName -> Text
epNameToTezosEp

instance CmdArg Mutez where
  toCmdArg :: Mutez -> String
toCmdArg Mutez
m = Fixed E6 -> String
forall b a. (PrettyShow a, Show a, IsString b) => a -> b
show (Fixed E6 -> String) -> (Integer -> Fixed E6) -> Integer -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k (a :: k). Integer -> Fixed a
MkFixed @_ @E6 (Integer -> String) -> Integer -> String
forall a b. (a -> b) -> a -> b
$ Word63 -> Integer
forall a b. (Integral a, Integral b, CheckIntSubType a b) => a -> b
fromIntegral (Mutez -> Word63
unMutez Mutez
m)

instance T.ProperUntypedValBetterErrors t => CmdArg (Value t) where
  toCmdArg :: Value t -> String
toCmdArg = LText -> String
forall a. CmdArg a => a -> String
toCmdArg (LText -> String) -> (Value t -> LText) -> Value t -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Value t -> LText
forall (t :: T).
ProperUntypedValBetterErrors t =>
Bool -> Value t -> LText
printTypedValue Bool
True

instance CmdArg (Contract cp st) where
  toCmdArg :: Contract cp st -> String
toCmdArg = LText -> String
forall a. ToString a => a -> String
toString (LText -> String)
-> (Contract cp st -> LText) -> Contract cp st -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Contract cp st -> LText
forall (p :: T) (s :: T). Bool -> Contract p s -> LText
printTypedContract Bool
True

instance CmdArg BaseUrl where
  toCmdArg :: BaseUrl -> String
toCmdArg = BaseUrl -> String
showBaseUrl

instance CmdArg OperationHash

instance CmdArg (Alias kind) where

instance CmdArg (AddressOrAlias kind) where

-- | Representation of address secret key encryption type
data SecretKeyEncryption
  = UnencryptedKey
  | EncryptedKey
  | LedgerKey
  deriving stock (SecretKeyEncryption -> SecretKeyEncryption -> Bool
(SecretKeyEncryption -> SecretKeyEncryption -> Bool)
-> (SecretKeyEncryption -> SecretKeyEncryption -> Bool)
-> Eq SecretKeyEncryption
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SecretKeyEncryption -> SecretKeyEncryption -> Bool
$c/= :: SecretKeyEncryption -> SecretKeyEncryption -> Bool
== :: SecretKeyEncryption -> SecretKeyEncryption -> Bool
$c== :: SecretKeyEncryption -> SecretKeyEncryption -> Bool
Eq, Int -> SecretKeyEncryption -> ShowS
[SecretKeyEncryption] -> ShowS
SecretKeyEncryption -> String
(Int -> SecretKeyEncryption -> ShowS)
-> (SecretKeyEncryption -> String)
-> ([SecretKeyEncryption] -> ShowS)
-> Show SecretKeyEncryption
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SecretKeyEncryption] -> ShowS
$cshowList :: [SecretKeyEncryption] -> ShowS
show :: SecretKeyEncryption -> String
$cshow :: SecretKeyEncryption -> String
showsPrec :: Int -> SecretKeyEncryption -> ShowS
$cshowsPrec :: Int -> SecretKeyEncryption -> ShowS
Show)

-- | Configuration maintained by @octez-client@, see its @config@ subcommands
-- (e. g. @octez-client config show@).
-- Only the field we are interested in is present here.
newtype TezosClientConfig = TezosClientConfig { TezosClientConfig -> BaseUrl
tcEndpointUrl :: BaseUrl }
  deriving stock Int -> TezosClientConfig -> ShowS
[TezosClientConfig] -> ShowS
TezosClientConfig -> String
(Int -> TezosClientConfig -> ShowS)
-> (TezosClientConfig -> String)
-> ([TezosClientConfig] -> ShowS)
-> Show TezosClientConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TezosClientConfig] -> ShowS
$cshowList :: [TezosClientConfig] -> ShowS
show :: TezosClientConfig -> String
$cshow :: TezosClientConfig -> String
showsPrec :: Int -> TezosClientConfig -> ShowS
$cshowsPrec :: Int -> TezosClientConfig -> ShowS
Show

-- | For reading @octez-client@ config.
instance FromJSON TezosClientConfig where
  parseJSON :: Value -> Parser TezosClientConfig
parseJSON = String
-> (Object -> Parser TezosClientConfig)
-> Value
-> Parser TezosClientConfig
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"node info" ((Object -> Parser TezosClientConfig)
 -> Value -> Parser TezosClientConfig)
-> (Object -> Parser TezosClientConfig)
-> Value
-> Parser TezosClientConfig
forall a b. (a -> b) -> a -> b
$ \Object
o -> BaseUrl -> TezosClientConfig
TezosClientConfig (BaseUrl -> TezosClientConfig)
-> Parser BaseUrl -> Parser TezosClientConfig
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Key -> Parser BaseUrl
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"endpoint"

-- | Runtime environment for @octez-client@ bindings.
data TezosClientEnv = TezosClientEnv
  { TezosClientEnv -> BaseUrl
tceEndpointUrl :: BaseUrl
  -- ^ URL of tezos node on which operations are performed.
  , TezosClientEnv -> String
tceTezosClientPath :: FilePath
  -- ^ Path to tezos client binary through which operations are
  -- performed.
  , TezosClientEnv -> Maybe String
tceMbTezosClientDataDir :: Maybe FilePath
  -- ^ Path to tezos client data directory.
  }

makeLensesWith postfixLFields ''TezosClientEnv

-- | Using this type class one can require 'MonadReader' constraint
-- that holds any type with 'TezosClientEnv' inside.
class HasTezosClientEnv env where
  tezosClientEnvL :: Lens' env TezosClientEnv

-- | Data required for calculating fee for transfer operation.
data CalcTransferFeeData = forall t kind. T.UntypedValScope t => CalcTransferFeeData
  { ()
ctfdTo :: AddressOrAlias kind
  , ()
ctfdParam :: Value t
  , CalcTransferFeeData -> EpName
ctfdEp :: EpName
  , CalcTransferFeeData -> TezosMutez
ctfdAmount :: TezosMutez
  }

instance ToJSON CalcTransferFeeData where
  toJSON :: CalcTransferFeeData -> Value
toJSON CalcTransferFeeData{AddressOrAlias kind
TezosMutez
Value t
EpName
ctfdAmount :: TezosMutez
ctfdEp :: EpName
ctfdParam :: Value t
ctfdTo :: AddressOrAlias kind
ctfdAmount :: CalcTransferFeeData -> TezosMutez
ctfdEp :: CalcTransferFeeData -> EpName
ctfdParam :: ()
ctfdTo :: ()
..} = [Pair] -> Value
object
    [ Key
"destination" Key -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= forall a b. (Buildable a, FromBuilder b) => a -> b
pretty @_ @Text AddressOrAlias kind
ctfdTo
    , Key
"amount" Key -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (forall a. IsString a => String -> a
fromString @Text (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Mutez -> String
forall a. CmdArg a => a -> String
toCmdArg (Mutez -> String) -> Mutez -> String
forall a b. (a -> b) -> a -> b
$ TezosMutez -> Mutez
unTezosMutez TezosMutez
ctfdAmount)
    , Key
"arg" Key -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (forall a. IsString a => String -> a
fromString @Text (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Value t -> String
forall a. CmdArg a => a -> String
toCmdArg Value t
ctfdParam)
    , Key
"entrypoint" Key -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (forall a. IsString a => String -> a
fromString @Text (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ EpName -> String
forall a. CmdArg a => a -> String
toCmdArg EpName
ctfdEp)
    ]

-- | Data required for calculating fee for origination operation.
data CalcOriginationFeeData cp st = forall kind. CalcOriginationFeeData
  { ()
cofdFrom :: AddressOrAlias kind
  , forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> TezosMutez
cofdBalance :: TezosMutez
  , forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> Maybe ScrubbedBytes
cofdMbFromPassword :: Maybe ScrubbedBytes
  , forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> Contract cp st
cofdContract :: Contract cp st
  , forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> Value st
cofdStorage :: Value st
  , forall (cp :: T) (st :: T).
CalcOriginationFeeData cp st -> TezosInt64
cofdBurnCap :: TezosInt64
  }