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

-- | Functions to reveal keys via node RPC.
module Morley.Client.Action.Reveal
  ( RevealData (..)
  , revealKey
  , revealKeyUnlessRevealed
  ) where

import Fmt ((|+))

import Morley.Client.Action.Common hiding (revealKeyUnlessRevealed)
import Morley.Client.Action.Operation
import Morley.Client.Logging
import Morley.Client.RPC.Class
import Morley.Client.RPC.Error
import Morley.Client.RPC.Getters
import Morley.Client.RPC.Types
import Morley.Client.TezosClient (HasTezosClient)
import Morley.Client.Types
import Morley.Tezos.Address
import Morley.Tezos.Address.Alias (AddressOrAlias(..))

-- | Reveal given key.
--
-- This is a variation of key revealing method that tries to use solely RPC.
-- TODO [#873] remove HasTezosClient dependency
revealKey
  :: forall m env.
     ( HasTezosRpc m
     , HasTezosClient m
     , WithClientLog env m
     )
  => ImplicitAddress
  -> RevealData
  -> m OperationHash
revealKey :: forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddress -> RevealData -> m OperationHash
revealKey ImplicitAddress
sender RevealData
revealing = do
  (Maybe OperationHash
mOpHash, [OperationInfo Result]
_) <- ImplicitAddressOrAlias
-> [OperationInfo ClientInput]
-> m (Maybe OperationHash, [OperationInfo Result])
forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddressOrAlias
-> [OperationInfo ClientInput]
-> m (Maybe OperationHash, [OperationInfo Result])
runOperations (ImplicitAddress -> ImplicitAddressOrAlias
forall (kind :: AddressKind).
KindedAddress kind -> AddressOrAlias kind
AddressResolved ImplicitAddress
sender) [RevealInfo ClientInput -> OperationInfo ClientInput
forall i. RevealInfo i -> OperationInfo i
OpReveal RevealInfo ClientInput
RevealData
revealing]
  case Maybe OperationHash
mOpHash of
    Just OperationHash
hash -> OperationHash -> m OperationHash
forall (m :: * -> *) a. Monad m => a -> m a
return OperationHash
hash
    Maybe OperationHash
_ -> IncorrectRpcResponse -> m OperationHash
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM IncorrectRpcResponse
RpcNoOperationsRun

-- | Reveal given key.
-- TODO [#873] remove HasTezosClient dependency
revealKeyUnlessRevealed
  :: forall m env.
     ( HasTezosRpc m
     , HasTezosClient m
     , WithClientLog env m
     )
  => ImplicitAddress
  -> RevealData
  -> m ()
revealKeyUnlessRevealed :: forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddress -> RevealData -> m ()
revealKeyUnlessRevealed ImplicitAddress
sender RevealData
param = do
  -- An optimization for the average case, but we can't rely on it in
  -- distributed environment
  Maybe PublicKey
mManagerKey <- ImplicitAddress -> m (Maybe PublicKey)
forall (m :: * -> *).
HasTezosRpc m =>
ImplicitAddress -> m (Maybe PublicKey)
getManagerKey ImplicitAddress
sender
  case Maybe PublicKey
mManagerKey of
    Just PublicKey
_  -> Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ ImplicitAddress
sender ImplicitAddress -> Builder -> Text
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
" address has already revealed key"
    Maybe PublicKey
Nothing -> m () -> m ()
forall {m :: * -> *}. MonadCatch m => m () -> m ()
ignoreAlreadyRevealedError (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ m OperationHash -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ImplicitAddress -> RevealData -> m OperationHash
forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddress -> RevealData -> m OperationHash
revealKey ImplicitAddress
sender RevealData
param)
  where
    ignoreAlreadyRevealedError :: m () -> m ()
ignoreAlreadyRevealedError m ()
action =
      m ()
action m () -> (RunCodeErrors -> m ()) -> m ()
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`catch` \case
        RunCodeErrors [PreviouslyRevealedKey ImplicitAddress
_] -> m ()
forall (f :: * -> *). Applicative f => f ()
pass
        RunCodeErrors
e -> RunCodeErrors -> m ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM RunCodeErrors
e