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

-- | Implementation of generic operations submission.
module Morley.Client.Action.Operation
  ( Result
  , runOperations
  , runOperationsNonEmpty
  -- * helpers
  , dryRunOperationsNonEmpty
  ) where

import Control.Lens (has, (%=), (&~))
import Data.List (zipWith4)
import Data.List.NonEmpty qualified as NE
import Data.Ratio ((%))
import Data.Singletons (Sing, SingI, sing)
import Data.Text qualified as T
import Fmt (blockListF, blockListF', listF, nameF, pretty, (+|), (|+))

import Morley.Client.Action.Common
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
import Morley.Client.Types
import Morley.Micheline (StringEncode(..), TezosInt64, TezosMutez(..))
import Morley.Tezos.Address
import Morley.Tezos.Address.Alias
import Morley.Tezos.Core
import Morley.Tezos.Crypto
import Morley.Util.ByteString
import Morley.Util.Constrained
import Morley.Util.Named

-- | Designates output of an operation.
data Result
instance OperationInfoDescriptor Result where
  type TransferInfo Result = [IntOpEvent]
  type OriginationInfo Result = ContractAddress
  type RevealInfo Result = ()
  type DelegationInfo Result = ()

logOperations
  :: forall (runMode :: RunMode) env m kind.
     ( WithClientLog env m
     , HasTezosClient m
     , MonadThrow m
     , SingI runMode -- We don't ask aliases with @octez-client@ in 'DryRun' mode
     , L1AddressKind kind
     )
  => AddressOrAlias kind
  -> NonEmpty (OperationInfo ClientInput)
  -> m ()
logOperations :: forall (runMode :: RunMode) env (m :: * -> *)
       (kind :: AddressKind).
(WithClientLog env m, HasTezosClient m, MonadThrow m,
 SingI runMode, L1AddressKind kind) =>
AddressOrAlias kind -> NonEmpty (OperationInfo ClientInput) -> m ()
logOperations AddressOrAlias kind
sender NonEmpty (OperationInfo ClientInput)
ops = do
  let runMode :: Sing runMode
runMode = forall {k} (a :: k). SingI a => Sing a
forall (a :: RunMode). SingI a => Sing a
sing @runMode

      opName :: Builder
opName =
        if | (Element (NonEmpty (OperationInfo ClientInput)) -> Bool)
-> NonEmpty (OperationInfo ClientInput) -> Bool
forall t. Container t => (Element t -> Bool) -> t -> Bool
all (Getting Any (OperationInfo ClientInput) TransactionData
-> OperationInfo ClientInput -> Bool
forall s a. Getting Any s a -> s -> Bool
has Getting Any (OperationInfo ClientInput) TransactionData
forall i. Prism' (OperationInfo i) (TransferInfo i)
_OpTransfer) NonEmpty (OperationInfo ClientInput)
ops -> Builder
"transactions"
           | (Element (NonEmpty (OperationInfo ClientInput)) -> Bool)
-> NonEmpty (OperationInfo ClientInput) -> Bool
forall t. Container t => (Element t -> Bool) -> t -> Bool
all (Getting Any (OperationInfo ClientInput) OriginationData
-> OperationInfo ClientInput -> Bool
forall s a. Getting Any s a -> s -> Bool
has Getting Any (OperationInfo ClientInput) OriginationData
forall i. Prism' (OperationInfo i) (OriginationInfo i)
_OpOriginate) NonEmpty (OperationInfo ClientInput)
ops -> Builder
"originations"
           | (Element (NonEmpty (OperationInfo ClientInput)) -> Bool)
-> NonEmpty (OperationInfo ClientInput) -> Bool
forall t. Container t => (Element t -> Bool) -> t -> Bool
all (Getting Any (OperationInfo ClientInput) RevealData
-> OperationInfo ClientInput -> Bool
forall s a. Getting Any s a -> s -> Bool
has Getting Any (OperationInfo ClientInput) RevealData
forall i. Prism' (OperationInfo i) (RevealInfo i)
_OpReveal) NonEmpty (OperationInfo ClientInput)
ops -> Builder
"reveals"
           | Bool
otherwise -> Builder
"operations"

      buildOp :: (OperationInfo ClientInput, Maybe Text) -> Builder
buildOp = \case
        (OpTransfer TransferInfo ClientInput
tx, Maybe Text
mbAlias) ->
          Maybe Text -> TransactionData -> Builder
buildTxDataWithAlias Maybe Text
mbAlias TransferInfo ClientInput
TransactionData
tx
        (OpOriginate OriginationInfo ClientInput
orig, Maybe Text
_) ->
          OriginationData -> ContractAlias
odName OriginationInfo ClientInput
OriginationData
orig ContractAlias -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
" (temporary alias)"
        (OpReveal RevealInfo ClientInput
rv, Maybe Text
mbAlias) ->
          Builder
"Key " Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+| RevealData -> PublicKey
rdPublicKey RevealInfo ClientInput
RevealData
rv PublicKey -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder -> (Text -> Builder) -> Maybe Text -> Builder
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Builder
"" (\Text
a -> Builder
" (" Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+| Text
a Text -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
")") Maybe Text
mbAlias
        (OpDelegation DelegationInfo ClientInput
delegate, Maybe Text
mbAlias) ->
          Builder
"Key Hash " Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+| DelegationData -> Maybe KeyHash
ddDelegate DelegationInfo ClientInput
DelegationData
delegate Maybe KeyHash -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder -> (Text -> Builder) -> Maybe Text -> Builder
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Builder
"" (\Text
a -> Builder
" (" Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+| Text
a Text -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
")") Maybe Text
mbAlias

  AddressOrAlias kind
sender' <- case AddressOrAlias kind
sender of
    addr :: AddressOrAlias kind
addr@AddressResolved{} -> case Sing runMode
runMode of
      Sing runMode
SingRunResult runMode
SRealRun -> Alias kind -> AddressOrAlias kind
forall (kind :: AddressKind). Alias kind -> AddressOrAlias kind
AddressAlias (Alias kind -> AddressOrAlias kind)
-> m (Alias kind) -> m (AddressOrAlias kind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AddressOrAlias kind -> m (ResolvedAlias (AddressOrAlias kind))
forall addressOrAlias (m :: * -> *) env.
(HasTezosClient m, WithClientLog env m, MonadThrow m,
 Resolve addressOrAlias) =>
addressOrAlias -> m (ResolvedAlias addressOrAlias)
getAlias AddressOrAlias kind
sender
      Sing runMode
SingRunResult runMode
SDryRun  -> AddressOrAlias kind -> m (AddressOrAlias kind)
forall (f :: * -> *) a. Applicative f => a -> f a
pure AddressOrAlias kind
addr
    AddressOrAlias kind
alias -> AddressOrAlias kind -> m (AddressOrAlias kind)
forall (f :: * -> *) a. Applicative f => a -> f a
pure AddressOrAlias kind
alias

  NonEmpty (Maybe Text)
aliases <- case Sing runMode
runMode of
    Sing runMode
SingRunResult runMode
SRealRun ->
      NonEmpty (OperationInfo ClientInput)
-> (OperationInfo ClientInput -> m (Maybe Text))
-> m (NonEmpty (Maybe Text))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM NonEmpty (OperationInfo ClientInput)
ops ((OperationInfo ClientInput -> m (Maybe Text))
 -> m (NonEmpty (Maybe Text)))
-> (OperationInfo ClientInput -> m (Maybe Text))
-> m (NonEmpty (Maybe Text))
forall a b. (a -> b) -> a -> b
$ \case
        OpTransfer (TransactionData TD (Value t)
tx) -> Constrained
  (ConstrainAddressKind
     '[ 'AddressKindImplicit, 'AddressKindContract])
  KindedAddress
-> (forall (t :: AddressKind).
    ConstrainAddressKind
      '[ 'AddressKindImplicit, 'AddressKindContract] t =>
    KindedAddress t -> m (Maybe Text))
-> m (Maybe Text)
forall {k} (c :: k -> Constraint) (f :: k -> *) r.
Constrained c f -> (forall (t :: k). c t => f t -> r) -> r
withConstrained (TD (Value t)
-> Constrained
     (ConstrainAddressKind
        '[ 'AddressKindImplicit, 'AddressKindContract])
     KindedAddress
forall t.
TD t
-> Constrained
     (ConstrainAddressKind
        '[ 'AddressKindImplicit, 'AddressKindContract])
     KindedAddress
tdReceiver TD (Value t)
tx) ((forall (t :: AddressKind).
  ConstrainAddressKind
    '[ 'AddressKindImplicit, 'AddressKindContract] t =>
  KindedAddress t -> m (Maybe Text))
 -> m (Maybe Text))
-> (forall (t :: AddressKind).
    ConstrainAddressKind
      '[ 'AddressKindImplicit, 'AddressKindContract] t =>
    KindedAddress t -> m (Maybe Text))
-> m (Maybe Text)
forall a b. (a -> b) -> a -> b
$
          (Alias t -> Maybe Text) -> m (Alias t) -> m (Maybe Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> (Alias t -> Text) -> Alias t -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Alias t -> Text
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty) (m (Alias t) -> m (Maybe Text))
-> (KindedAddress t -> m (Alias t))
-> KindedAddress t
-> m (Maybe Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AddressOrAlias t -> m (Alias t)
forall addressOrAlias (m :: * -> *) env.
(HasTezosClient m, WithClientLog env m, MonadThrow m,
 Resolve addressOrAlias) =>
addressOrAlias -> m (ResolvedAlias addressOrAlias)
getAlias (AddressOrAlias t -> m (Alias t))
-> (KindedAddress t -> AddressOrAlias t)
-> KindedAddress t
-> m (Alias t)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KindedAddress t -> AddressOrAlias t
forall (kind :: AddressKind).
L1AddressKind kind =>
KindedAddress kind -> AddressOrAlias kind
AddressResolved
        OpOriginate OriginationInfo ClientInput
_ ->
          Maybe Text -> m (Maybe Text)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Text
forall a. Maybe a
Nothing
        OpReveal RevealInfo ClientInput
r ->
          Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text)
-> (Alias 'AddressKindImplicit -> Text)
-> Alias 'AddressKindImplicit
-> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Alias 'AddressKindImplicit -> Text
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty (Alias 'AddressKindImplicit -> Maybe Text)
-> m (Alias 'AddressKindImplicit) -> m (Maybe Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (AddressOrAlias 'AddressKindImplicit
-> m (Alias 'AddressKindImplicit)
forall addressOrAlias (m :: * -> *) env.
(HasTezosClient m, WithClientLog env m, MonadThrow m,
 Resolve addressOrAlias) =>
addressOrAlias -> m (ResolvedAlias addressOrAlias)
getAlias (AddressOrAlias 'AddressKindImplicit
 -> m (Alias 'AddressKindImplicit))
-> (PublicKey -> AddressOrAlias 'AddressKindImplicit)
-> PublicKey
-> m (Alias 'AddressKindImplicit)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KindedAddress 'AddressKindImplicit
-> AddressOrAlias 'AddressKindImplicit
forall (kind :: AddressKind).
L1AddressKind kind =>
KindedAddress kind -> AddressOrAlias kind
AddressResolved (KindedAddress 'AddressKindImplicit
 -> AddressOrAlias 'AddressKindImplicit)
-> (PublicKey -> KindedAddress 'AddressKindImplicit)
-> PublicKey
-> AddressOrAlias 'AddressKindImplicit
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PublicKey -> KindedAddress 'AddressKindImplicit
mkKeyAddress (PublicKey -> m (Alias 'AddressKindImplicit))
-> PublicKey -> m (Alias 'AddressKindImplicit)
forall a b. (a -> b) -> a -> b
$ RevealData -> PublicKey
rdPublicKey RevealInfo ClientInput
RevealData
r)
        OpDelegation DelegationInfo ClientInput
d ->
          m (Maybe Text)
-> (KeyHash -> m (Maybe Text)) -> Maybe KeyHash -> m (Maybe Text)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Maybe Text -> m (Maybe Text)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Text
forall a. Maybe a
Nothing)
                ((Alias 'AddressKindImplicit -> Maybe Text)
-> m (Alias 'AddressKindImplicit) -> m (Maybe Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text)
-> (Alias 'AddressKindImplicit -> Text)
-> Alias 'AddressKindImplicit
-> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Alias 'AddressKindImplicit -> Text
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty) (m (Alias 'AddressKindImplicit) -> m (Maybe Text))
-> (KeyHash -> m (Alias 'AddressKindImplicit))
-> KeyHash
-> m (Maybe Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AddressOrAlias 'AddressKindImplicit
-> m (Alias 'AddressKindImplicit)
forall addressOrAlias (m :: * -> *) env.
(HasTezosClient m, WithClientLog env m, MonadThrow m,
 Resolve addressOrAlias) =>
addressOrAlias -> m (ResolvedAlias addressOrAlias)
getAlias (AddressOrAlias 'AddressKindImplicit
 -> m (Alias 'AddressKindImplicit))
-> (KeyHash -> AddressOrAlias 'AddressKindImplicit)
-> KeyHash
-> m (Alias 'AddressKindImplicit)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KindedAddress 'AddressKindImplicit
-> AddressOrAlias 'AddressKindImplicit
forall (kind :: AddressKind).
L1AddressKind kind =>
KindedAddress kind -> AddressOrAlias kind
AddressResolved (KindedAddress 'AddressKindImplicit
 -> AddressOrAlias 'AddressKindImplicit)
-> (KeyHash -> KindedAddress 'AddressKindImplicit)
-> KeyHash
-> AddressOrAlias 'AddressKindImplicit
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KeyHash -> KindedAddress 'AddressKindImplicit
ImplicitAddress) (Maybe KeyHash -> m (Maybe Text))
-> Maybe KeyHash -> m (Maybe Text)
forall a b. (a -> b) -> a -> b
$ DelegationData -> Maybe KeyHash
ddDelegate DelegationInfo ClientInput
DelegationData
d
    Sing runMode
SingRunResult runMode
SDryRun -> NonEmpty (Maybe Text) -> m (NonEmpty (Maybe Text))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (NonEmpty (Maybe Text) -> m (NonEmpty (Maybe Text)))
-> NonEmpty (Maybe Text) -> m (NonEmpty (Maybe Text))
forall a b. (a -> b) -> a -> b
$ NonEmpty (OperationInfo ClientInput)
ops NonEmpty (OperationInfo ClientInput)
-> Maybe Text -> NonEmpty (Maybe Text)
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> Maybe Text
forall a. Maybe a
Nothing

  Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logInfo (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> Text
T.strip (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ -- strip trailing newline
    Builder
"Running " Builder -> Builder -> Text
forall b. FromBuilder b => Builder -> Builder -> b
+| Builder
opName Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+| Builder
" by " Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+| AddressOrAlias kind
sender' AddressOrAlias kind -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
":\n" Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+|
    Text
-> ((OperationInfo ClientInput, Maybe Text) -> Builder)
-> NonEmpty (OperationInfo ClientInput, Maybe Text)
-> Builder
forall (f :: * -> *) a.
Foldable f =>
Text -> (a -> Builder) -> f a -> Builder
blockListF' Text
"-" (OperationInfo ClientInput, Maybe Text) -> Builder
buildOp (NonEmpty (OperationInfo ClientInput)
ops NonEmpty (OperationInfo ClientInput)
-> NonEmpty (Maybe Text)
-> NonEmpty (OperationInfo ClientInput, Maybe Text)
forall a b. NonEmpty a -> NonEmpty b -> NonEmpty (a, b)
`NE.zip` NonEmpty (Maybe Text)
aliases)

-- | Perform sequence of operations.
--
-- Returns operation hash (or @Nothing@ in case empty list was provided) and result of
-- each operation (nothing for transactions and an address for originated contracts
runOperations
  :: forall m env.
     ( HasTezosRpc m
     , HasTezosClient m
     , WithClientLog env m
     )
  => ImplicitAddressOrAlias
  -> [OperationInfo ClientInput]
  -> m (Maybe OperationHash, [OperationInfo Result])
runOperations :: forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
AddressOrAlias 'AddressKindImplicit
-> [OperationInfo ClientInput]
-> m (Maybe OperationHash, [OperationInfo Result])
runOperations AddressOrAlias 'AddressKindImplicit
sender [OperationInfo ClientInput]
operations = case [OperationInfo ClientInput]
operations of
  [] -> (Maybe OperationHash, [OperationInfo Result])
-> m (Maybe OperationHash, [OperationInfo Result])
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe OperationHash
forall a. Maybe a
Nothing, [])
  OperationInfo ClientInput
op : [OperationInfo ClientInput]
ops -> do
    (OperationHash
opHash, NonEmpty (OperationInfo Result)
res) <- AddressOrAlias 'AddressKindImplicit
-> NonEmpty (OperationInfo ClientInput)
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
AddressOrAlias 'AddressKindImplicit
-> NonEmpty (OperationInfo ClientInput)
-> m (OperationHash, NonEmpty (OperationInfo Result))
runOperationsNonEmpty AddressOrAlias 'AddressKindImplicit
sender (NonEmpty (OperationInfo ClientInput)
 -> m (OperationHash, NonEmpty (OperationInfo Result)))
-> NonEmpty (OperationInfo ClientInput)
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall a b. (a -> b) -> a -> b
$ OperationInfo ClientInput
op OperationInfo ClientInput
-> [OperationInfo ClientInput]
-> NonEmpty (OperationInfo ClientInput)
forall a. a -> [a] -> NonEmpty a
:| [OperationInfo ClientInput]
ops
    (Maybe OperationHash, [OperationInfo Result])
-> m (Maybe OperationHash, [OperationInfo Result])
forall (m :: * -> *) a. Monad m => a -> m a
return ((Maybe OperationHash, [OperationInfo Result])
 -> m (Maybe OperationHash, [OperationInfo Result]))
-> (Maybe OperationHash, [OperationInfo Result])
-> m (Maybe OperationHash, [OperationInfo Result])
forall a b. (a -> b) -> a -> b
$ (OperationHash -> Maybe OperationHash
forall a. a -> Maybe a
Just OperationHash
opHash, NonEmpty (OperationInfo Result)
-> [Element (NonEmpty (OperationInfo Result))]
forall t. Container t => t -> [Element t]
toList NonEmpty (OperationInfo Result)
res)

-- | How many times to retry if an operation fails after injection
injectionRetryCount :: Natural
injectionRetryCount :: Natural
injectionRetryCount = Natural
2

-- | Perform non-empty sequence of operations.
--
-- Returns operation hash and result of each operation
-- (nothing for transactions and an address for originated contracts).
runOperationsNonEmpty
  :: forall m env.
     ( HasTezosRpc m
     , HasTezosClient m
     , WithClientLog env m
     )
  => ImplicitAddressOrAlias
  -> NonEmpty (OperationInfo ClientInput)
  -> m (OperationHash, NonEmpty (OperationInfo Result))
runOperationsNonEmpty :: forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
AddressOrAlias 'AddressKindImplicit
-> NonEmpty (OperationInfo ClientInput)
-> m (OperationHash, NonEmpty (OperationInfo Result))
runOperationsNonEmpty AddressOrAlias 'AddressKindImplicit
sender NonEmpty (OperationInfo ClientInput)
operations =
  forall (runMode :: RunMode) (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 SingI runMode) =>
Natural
-> AddressOrAlias 'AddressKindImplicit
-> NonEmpty (OperationInfo ClientInput)
-> m (RunResult runMode)
runOperationsNonEmptyHelper @'RealRun Natural
injectionRetryCount AddressOrAlias 'AddressKindImplicit
sender NonEmpty (OperationInfo ClientInput)
operations

-- | Flag that is used to determine @runOperationsNonEmptyHelper@ behaviour.
data RunMode = DryRun | RealRun

isRealRun :: forall (runMode :: RunMode). (SingI runMode) => Bool
isRealRun :: forall (runMode :: RunMode). SingI runMode => Bool
isRealRun = case forall {k} (a :: k). SingI a => Sing a
forall (a :: RunMode). SingI a => Sing a
sing @runMode of
  Sing runMode
SingRunResult runMode
SRealRun -> Bool
True
  Sing runMode
SingRunResult runMode
SDryRun  -> Bool
False

-- | Type family which is used to determine the output type of the
-- @runOperationsNonEmptyHelper@.
type family RunResult (a :: RunMode) where
  RunResult 'DryRun = NonEmpty (AppliedResult, TezosMutez)
  RunResult 'RealRun = (OperationHash, NonEmpty (OperationInfo Result))

data SingRunResult :: RunMode -> Type where
  SDryRun :: SingRunResult 'DryRun
  SRealRun :: SingRunResult 'RealRun

type instance Sing = SingRunResult

instance SingI 'DryRun where
  sing :: Sing 'DryRun
sing = Sing 'DryRun
SingRunResult 'DryRun
SDryRun

instance SingI 'RealRun where
  sing :: Sing 'RealRun
sing = Sing 'RealRun
SingRunResult 'RealRun
SRealRun

-- | Perform dry-run for sequence of operations.
--
-- Returned @AppliedResult@ contains information about estimated limits,
-- storage changes, etc. Additionally, estimated fees are returned.
dryRunOperationsNonEmpty
  :: forall m env.
     ( HasTezosRpc m
     , HasTezosClient m
     , WithClientLog env m
     )
  => ImplicitAddressOrAlias
  -> NonEmpty (OperationInfo ClientInput)
  -> m (NonEmpty (AppliedResult, TezosMutez))
dryRunOperationsNonEmpty :: forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
AddressOrAlias 'AddressKindImplicit
-> NonEmpty (OperationInfo ClientInput)
-> m (NonEmpty (AppliedResult, TezosMutez))
dryRunOperationsNonEmpty AddressOrAlias 'AddressKindImplicit
sender NonEmpty (OperationInfo ClientInput)
operations =
  forall (runMode :: RunMode) (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 SingI runMode) =>
Natural
-> AddressOrAlias 'AddressKindImplicit
-> NonEmpty (OperationInfo ClientInput)
-> m (RunResult runMode)
runOperationsNonEmptyHelper @'DryRun Natural
0 AddressOrAlias 'AddressKindImplicit
sender NonEmpty (OperationInfo ClientInput)
operations

-- | Perform non-empty sequence of operations and either dry-run
-- and return estimated limits and fees or perform operation injection.
-- Behaviour is defined via @RunMode@ flag argument.
runOperationsNonEmptyHelper
  :: forall (runMode :: RunMode) m env.
     ( HasTezosRpc m
     , HasTezosClient m
     , WithClientLog env m
     , SingI runMode
     )
  => Natural
  -> ImplicitAddressOrAlias
  -> NonEmpty (OperationInfo ClientInput)
  -> m (RunResult runMode)
runOperationsNonEmptyHelper :: forall (runMode :: RunMode) (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 SingI runMode) =>
Natural
-> AddressOrAlias 'AddressKindImplicit
-> NonEmpty (OperationInfo ClientInput)
-> m (RunResult runMode)
runOperationsNonEmptyHelper Natural
retryCount AddressOrAlias 'AddressKindImplicit
sender NonEmpty (OperationInfo ClientInput)
operations = do
  forall (runMode :: RunMode) env (m :: * -> *)
       (kind :: AddressKind).
(WithClientLog env m, HasTezosClient m, MonadThrow m,
 SingI runMode, L1AddressKind kind) =>
AddressOrAlias kind -> NonEmpty (OperationInfo ClientInput) -> m ()
logOperations @runMode AddressOrAlias 'AddressKindImplicit
sender NonEmpty (OperationInfo ClientInput)
operations
  -- If we intend to fail on duplicate aliases, we want to fail now, rather than
  -- after contract origination.
  NonEmpty (OperationInfo ClientInput)
-> (Element (NonEmpty (OperationInfo ClientInput)) -> m ()) -> m ()
forall t (m :: * -> *) b.
(Container t, Monad m) =>
t -> (Element t -> m b) -> m ()
forM_ NonEmpty (OperationInfo ClientInput)
operations ((Element (NonEmpty (OperationInfo ClientInput)) -> m ()) -> m ())
-> (Element (NonEmpty (OperationInfo ClientInput)) -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \case
    OpOriginate OriginationData{odAliasBehavior :: OriginationData -> AliasBehavior
odAliasBehavior = AliasBehavior
ForbidDuplicateAlias, Maybe KeyHash
Maybe Mutez
ContractAlias
Mutez
Contract cp st
Value st
odMbFee :: OriginationData -> Maybe Mutez
odDelegate :: OriginationData -> Maybe KeyHash
odStorage :: ()
odContract :: ()
odBalance :: OriginationData -> Mutez
odMbFee :: Maybe Mutez
odDelegate :: Maybe KeyHash
odStorage :: Value st
odContract :: Contract cp st
odBalance :: Mutez
odName :: ContractAlias
odName :: OriginationData -> ContractAlias
..} -> do
      Maybe (KindedAddress 'AddressKindContract)
resolved <- AddressOrAlias 'AddressKindContract
-> m (Maybe
        (ResolvedAddress (AddressOrAlias 'AddressKindContract)))
forall addressOrAlias (m :: * -> *) env.
(HasTezosClient m, MonadThrow m, WithClientLog env m,
 Resolve addressOrAlias) =>
addressOrAlias -> m (Maybe (ResolvedAddress addressOrAlias))
resolveAddressMaybe (ContractAlias -> AddressOrAlias 'AddressKindContract
forall (kind :: AddressKind). Alias kind -> AddressOrAlias kind
AddressAlias ContractAlias
odName)
      Maybe (KindedAddress 'AddressKindContract)
-> (KindedAddress 'AddressKindContract -> m ()) -> m ()
forall (f :: * -> *) a.
Applicative f =>
Maybe a -> (a -> f ()) -> f ()
whenJust Maybe (KindedAddress 'AddressKindContract)
resolved ((KindedAddress 'AddressKindContract -> m ()) -> m ())
-> (KindedAddress 'AddressKindContract -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ m () -> KindedAddress 'AddressKindContract -> m ()
forall a b. a -> b -> a
const (m () -> KindedAddress 'AddressKindContract -> m ())
-> m () -> KindedAddress 'AddressKindContract -> m ()
forall a b. (a -> b) -> a -> b
$ TezosClientError -> m ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (TezosClientError -> m ()) -> TezosClientError -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> TezosClientError
DuplicateAlias (ContractAlias -> Text
forall (kind :: AddressKind). Alias kind -> Text
unAlias ContractAlias
odName)
    Element (NonEmpty (OperationInfo ClientInput))
_ -> m ()
forall (f :: * -> *). Applicative f => f ()
pass
  KindedAddress 'AddressKindImplicit
senderAddress <- AddressOrAlias 'AddressKindImplicit
-> m (ResolvedAddress (AddressOrAlias 'AddressKindImplicit))
forall addressOrAlias (m :: * -> *) env.
(HasTezosClient m, MonadThrow m, WithClientLog env m,
 Resolve addressOrAlias) =>
addressOrAlias -> m (ResolvedAddress addressOrAlias)
resolveAddress AddressOrAlias 'AddressKindImplicit
sender
  Maybe ScrubbedBytes
mbPassword <- KindedAddress 'AddressKindImplicit -> m (Maybe ScrubbedBytes)
forall (m :: * -> *).
HasTezosClient m =>
KindedAddress 'AddressKindImplicit -> m (Maybe ScrubbedBytes)
getKeyPassword KindedAddress 'AddressKindImplicit
senderAddress
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall (runMode :: RunMode). SingI runMode => Bool
isRealRun @runMode Bool -> Bool -> Bool
forall a. Boolean a => a -> a -> a
&& [OperationInfo ClientInput] -> Bool
forall i. [OperationInfo i] -> Bool
mayNeedSenderRevealing (NonEmpty (OperationInfo ClientInput)
-> [Element (NonEmpty (OperationInfo ClientInput))]
forall t. Container t => t -> [Element t]
toList NonEmpty (OperationInfo ClientInput)
operations)) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
    KindedAddress 'AddressKindImplicit -> Maybe ScrubbedBytes -> m ()
forall env (m :: * -> *).
(WithClientLog env m, HasTezosRpc m, HasTezosClient m) =>
KindedAddress 'AddressKindImplicit -> Maybe ScrubbedBytes -> m ()
revealKeyUnlessRevealed KindedAddress 'AddressKindImplicit
senderAddress Maybe ScrubbedBytes
mbPassword

  ProtocolParameters
pp <- m ProtocolParameters
forall (m :: * -> *). HasTezosRpc m => m ProtocolParameters
getProtocolParameters
  OperationConstants{StringEncode Int64
FeeConstants
BlockHash
BlockConstants
ocCounter :: OperationConstants -> StringEncode Int64
ocFeeConstants :: OperationConstants -> FeeConstants
ocBlockConstants :: OperationConstants -> BlockConstants
ocLastBlockHash :: OperationConstants -> BlockHash
ocCounter :: StringEncode Int64
ocFeeConstants :: FeeConstants
ocBlockConstants :: BlockConstants
ocLastBlockHash :: BlockHash
..} <- KindedAddress 'AddressKindImplicit -> m OperationConstants
forall (m :: * -> *).
HasTezosRpc m =>
KindedAddress 'AddressKindImplicit -> m OperationConstants
preProcessOperation KindedAddress 'AddressKindImplicit
senderAddress

  let convertOps :: StringEncode Int64
-> OperationInfo ClientInput
-> WithCommonOperationData (OperationInfo RPCInput)
convertOps StringEncode Int64
i = CommonOperationData
-> OperationInfo RPCInput
-> WithCommonOperationData (OperationInfo RPCInput)
forall a. CommonOperationData -> a -> WithCommonOperationData a
WithCommonOperationData CommonOperationData
commonData (OperationInfo RPCInput
 -> WithCommonOperationData (OperationInfo RPCInput))
-> (OperationInfo ClientInput -> OperationInfo RPCInput)
-> OperationInfo ClientInput
-> WithCommonOperationData (OperationInfo RPCInput)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
        OpTransfer (TransactionData TD {tdReceiver :: forall t.
TD t
-> Constrained
     (ConstrainAddressKind
        '[ 'AddressKindImplicit, 'AddressKindContract])
     KindedAddress
tdReceiver=Constrained KindedAddress a
tdReceiver, Maybe Mutez
Mutez
Value t
EpName
tdMbFee :: forall t. TD t -> Maybe Mutez
tdParam :: forall t. TD t -> t
tdEpName :: forall t. TD t -> EpName
tdAmount :: forall t. TD t -> Mutez
tdMbFee :: Maybe Mutez
tdParam :: Value t
tdEpName :: EpName
tdAmount :: Mutez
..}) ->
          TransferInfo RPCInput -> OperationInfo RPCInput
forall i. TransferInfo i -> OperationInfo i
OpTransfer TransactionOperation :: TezosMutez -> Address -> ParametersInternal -> TransactionOperation
TransactionOperation
          { toDestination :: Address
toDestination = KindedAddress a -> Address
forall (kind :: AddressKind). KindedAddress kind -> Address
MkAddress KindedAddress a
tdReceiver
          , toAmount :: TezosMutez
toAmount = Mutez -> TezosMutez
TezosMutez Mutez
tdAmount
          , toParameters :: ParametersInternal
toParameters = EpName -> Value t -> ParametersInternal
forall (t :: T).
ParameterScope t =>
EpName -> Value t -> ParametersInternal
toParametersInternals EpName
tdEpName Value t
tdParam
          }
        OpOriginate OriginationData{Maybe KeyHash
Maybe Mutez
ContractAlias
AliasBehavior
Mutez
Contract cp st
Value st
odMbFee :: Maybe Mutez
odDelegate :: Maybe KeyHash
odStorage :: Value st
odContract :: Contract cp st
odBalance :: Mutez
odName :: ContractAlias
odAliasBehavior :: AliasBehavior
odMbFee :: OriginationData -> Maybe Mutez
odDelegate :: OriginationData -> Maybe KeyHash
odStorage :: ()
odContract :: ()
odBalance :: OriginationData -> Mutez
odAliasBehavior :: OriginationData -> AliasBehavior
odName :: OriginationData -> ContractAlias
..} ->
          OriginationInfo RPCInput -> OperationInfo RPCInput
forall i. OriginationInfo i -> OperationInfo i
OpOriginate OriginationOperation :: TezosMutez
-> Maybe KeyHash -> OriginationScript -> OriginationOperation
OriginationOperation
          { ooBalance :: TezosMutez
ooBalance = Mutez -> TezosMutez
TezosMutez Mutez
odBalance
          , ooDelegate :: Maybe KeyHash
ooDelegate = Maybe KeyHash
odDelegate
          , ooScript :: OriginationScript
ooScript = Contract cp st -> Value st -> OriginationScript
forall (cp :: T) (st :: T).
Contract cp st -> Value st -> OriginationScript
mkOriginationScript Contract cp st
odContract Value st
odStorage
          }
        OpReveal RevealData{Maybe Mutez
PublicKey
rdMbFee :: RevealData -> Maybe Mutez
rdMbFee :: Maybe Mutez
rdPublicKey :: PublicKey
rdPublicKey :: RevealData -> PublicKey
..} ->
          RevealInfo RPCInput -> OperationInfo RPCInput
forall i. RevealInfo i -> OperationInfo i
OpReveal RevealOperation :: PublicKey -> RevealOperation
RevealOperation
          { roPublicKey :: PublicKey
roPublicKey = PublicKey
rdPublicKey
          }
        OpDelegation DelegationData{Maybe KeyHash
Maybe Mutez
ddMbFee :: DelegationData -> Maybe Mutez
ddMbFee :: Maybe Mutez
ddDelegate :: Maybe KeyHash
ddDelegate :: DelegationData -> Maybe KeyHash
..} ->
          DelegationInfo RPCInput -> OperationInfo RPCInput
forall i. DelegationInfo i -> OperationInfo i
OpDelegation DelegationOperation :: Maybe KeyHash -> DelegationOperation
DelegationOperation
          { doDelegate :: Maybe KeyHash
doDelegate = Maybe KeyHash
ddDelegate
          }
        where
          commonData :: CommonOperationData
commonData = ProtocolParameters
-> NamedF Identity (KindedAddress 'AddressKindImplicit) "sender"
-> NamedF Identity (StringEncode Int64) "counter"
-> NamedF Maybe Int64 "num_operations"
-> CommonOperationData
mkCommonOperationData ProtocolParameters
pp
            (NamedF Identity (KindedAddress 'AddressKindImplicit) "sender"
 -> NamedF Identity (StringEncode Int64) "counter"
 -> NamedF Maybe Int64 "num_operations"
 -> CommonOperationData)
-> Param
     (NamedF Identity (KindedAddress 'AddressKindImplicit) "sender")
-> NamedF Identity (StringEncode Int64) "counter"
-> NamedF Maybe Int64 "num_operations"
-> CommonOperationData
forall p fn fn'. WithParam p fn fn' => fn -> Param p -> fn'
! IsLabel
  "sender"
  (KindedAddress 'AddressKindImplicit
   -> Param
        (NamedF Identity (KindedAddress 'AddressKindImplicit) "sender"))
KindedAddress 'AddressKindImplicit
-> Param
     (NamedF Identity (KindedAddress 'AddressKindImplicit) "sender")
#sender KindedAddress 'AddressKindImplicit
senderAddress
            (NamedF Identity (StringEncode Int64) "counter"
 -> NamedF Maybe Int64 "num_operations" -> CommonOperationData)
-> Param (NamedF Identity (StringEncode Int64) "counter")
-> NamedF Maybe Int64 "num_operations"
-> CommonOperationData
forall p fn fn'. WithParam p fn fn' => fn -> Param p -> fn'
! IsLabel
  "counter"
  (StringEncode Int64
   -> Param (NamedF Identity (StringEncode Int64) "counter"))
StringEncode Int64
-> Param (NamedF Identity (StringEncode Int64) "counter")
#counter (StringEncode Int64
ocCounter StringEncode Int64 -> StringEncode Int64 -> StringEncode Int64
forall a. Num a => a -> a -> a
+ StringEncode Int64
i)
            (NamedF Maybe Int64 "num_operations" -> CommonOperationData)
-> Param (NamedF Maybe Int64 "num_operations")
-> CommonOperationData
forall p fn fn'. WithParam p fn fn' => fn -> Param p -> fn'
! IsLabel
  "num_operations"
  (Int64 -> Param (NamedF Maybe Int64 "num_operations"))
Int64 -> Param (NamedF Maybe Int64 "num_operations")
#num_operations (Int -> Int64
forall a b. (Integral a, Integral b, CheckIntSubType a b) => a -> b
fromIntegral (NonEmpty (OperationInfo ClientInput) -> Int
forall t. Container t => t -> Int
length NonEmpty (OperationInfo ClientInput)
operations))

  let opsToRun :: NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
opsToRun = (StringEncode Int64
 -> OperationInfo ClientInput
 -> WithCommonOperationData (OperationInfo RPCInput))
-> NonEmpty (StringEncode Int64)
-> NonEmpty (OperationInfo ClientInput)
-> NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NE.zipWith StringEncode Int64
-> OperationInfo ClientInput
-> WithCommonOperationData (OperationInfo RPCInput)
convertOps (StringEncode Int64
1 StringEncode Int64
-> [StringEncode Int64] -> NonEmpty (StringEncode Int64)
forall a. a -> [a] -> NonEmpty a
:| [(StringEncode Int64
2 :: TezosInt64)..]) NonEmpty (OperationInfo ClientInput)
operations
      mbFees :: NonEmpty (Maybe Mutez)
mbFees = NonEmpty (OperationInfo ClientInput)
operations NonEmpty (OperationInfo ClientInput)
-> (OperationInfo ClientInput -> Maybe Mutez)
-> NonEmpty (Maybe Mutez)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
        OpTransfer (TransactionData TD {Maybe Mutez
Constrained
  (ConstrainAddressKind
     '[ 'AddressKindImplicit, 'AddressKindContract])
  KindedAddress
Mutez
Value t
EpName
tdMbFee :: Maybe Mutez
tdParam :: Value t
tdEpName :: EpName
tdAmount :: Mutez
tdReceiver :: Constrained
  (ConstrainAddressKind
     '[ 'AddressKindImplicit, 'AddressKindContract])
  KindedAddress
tdMbFee :: forall t. TD t -> Maybe Mutez
tdParam :: forall t. TD t -> t
tdEpName :: forall t. TD t -> EpName
tdAmount :: forall t. TD t -> Mutez
tdReceiver :: forall t.
TD t
-> Constrained
     (ConstrainAddressKind
        '[ 'AddressKindImplicit, 'AddressKindContract])
     KindedAddress
..}) -> Maybe Mutez
tdMbFee
        OpOriginate OriginationData{Maybe KeyHash
Maybe Mutez
ContractAlias
AliasBehavior
Mutez
Contract cp st
Value st
odMbFee :: Maybe Mutez
odDelegate :: Maybe KeyHash
odStorage :: Value st
odContract :: Contract cp st
odBalance :: Mutez
odName :: ContractAlias
odAliasBehavior :: AliasBehavior
odMbFee :: OriginationData -> Maybe Mutez
odDelegate :: OriginationData -> Maybe KeyHash
odStorage :: ()
odContract :: ()
odBalance :: OriginationData -> Mutez
odAliasBehavior :: OriginationData -> AliasBehavior
odName :: OriginationData -> ContractAlias
..} -> Maybe Mutez
odMbFee
        OpReveal RevealData{Maybe Mutez
PublicKey
rdMbFee :: Maybe Mutez
rdPublicKey :: PublicKey
rdMbFee :: RevealData -> Maybe Mutez
rdPublicKey :: RevealData -> PublicKey
..} -> Maybe Mutez
rdMbFee
        OpDelegation DelegationData {Maybe KeyHash
Maybe Mutez
ddMbFee :: Maybe Mutez
ddDelegate :: Maybe KeyHash
ddMbFee :: DelegationData -> Maybe Mutez
ddDelegate :: DelegationData -> Maybe KeyHash
..} -> Maybe Mutez
ddMbFee

  -- Perform run_operation with dumb signature in order
  -- to estimate gas cost, storage size and paid storage diff
  let runOp :: RunOperation
runOp = RunOperation :: RunOperationInternal -> Text -> RunOperation
RunOperation
        { roOperation :: RunOperationInternal
roOperation = RunOperationInternal :: BlockHash
-> NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
-> Signature
-> RunOperationInternal
RunOperationInternal
          { roiBranch :: BlockHash
roiBranch = BlockHash
ocLastBlockHash
          , roiContents :: NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
roiContents = NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
opsToRun
          , roiSignature :: Signature
roiSignature = Signature
stubSignature
          }
        , roChainId :: Text
roChainId = BlockConstants -> Text
bcChainId BlockConstants
ocBlockConstants
        }
  (NonEmpty AppliedResult
results, [InternalOperationData]
_) <- Either RunOperation PreApplyOperation
-> m (NonEmpty AppliedResult, [InternalOperationData])
forall (m :: * -> *).
HasTezosRpc m =>
Either RunOperation PreApplyOperation
-> m (NonEmpty AppliedResult, [InternalOperationData])
getAppliedResults (RunOperation -> Either RunOperation PreApplyOperation
forall a b. a -> Either a b
Left RunOperation
runOp)

  let -- Learn how to forge given operations
      forgeOp :: NonEmpty OperationInput -> m ByteString
      forgeOp :: NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
-> m ByteString
forgeOp NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
ops =
        (HexJSONByteString -> ByteString)
-> m HexJSONByteString -> m ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap HexJSONByteString -> ByteString
unHexJSONByteString (m HexJSONByteString -> m ByteString)
-> (ForgeOperation -> m HexJSONByteString)
-> ForgeOperation
-> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ForgeOperation -> m HexJSONByteString
forall (m :: * -> *).
HasTezosRpc m =>
ForgeOperation -> m HexJSONByteString
forgeOperation (ForgeOperation -> m ByteString) -> ForgeOperation -> m ByteString
forall a b. (a -> b) -> a -> b
$ ForgeOperation :: BlockHash
-> NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
-> ForgeOperation
ForgeOperation
          { foBranch :: BlockHash
foBranch = BlockHash
ocLastBlockHash
          , foContents :: NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
foContents = NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
ops
          }

  let -- Attach a signature to forged operation + return the signature itself
      signForgedOp :: ByteString -> m (Signature, ByteString)
      signForgedOp :: ByteString -> m (Signature, ByteString)
signForgedOp ByteString
op = do
        Signature
signature' <- AddressOrAlias 'AddressKindImplicit
-> Maybe ScrubbedBytes -> ByteString -> m Signature
forall (m :: * -> *).
HasTezosClient m =>
AddressOrAlias 'AddressKindImplicit
-> Maybe ScrubbedBytes -> ByteString -> m Signature
signBytes AddressOrAlias 'AddressKindImplicit
sender Maybe ScrubbedBytes
mbPassword (ByteString -> ByteString
addOperationPrefix ByteString
op)
        return (Signature
signature', ByteString -> Signature -> ByteString
prepareOpForInjection ByteString
op Signature
signature')

  -- Fill in fees
  let
    updateOp :: OperationInput -> Maybe Mutez -> AppliedResult -> Bool -> m (OperationInput, Maybe (Signature, ByteString))
    updateOp :: WithCommonOperationData (OperationInfo RPCInput)
-> Maybe Mutez
-> AppliedResult
-> Bool
-> m (WithCommonOperationData (OperationInfo RPCInput),
      Maybe (Signature, ByteString))
updateOp opToRun :: WithCommonOperationData (OperationInfo RPCInput)
opToRun@(WithCommonOperationData CommonOperationData
_ OperationInfo RPCInput
internalOp) Maybe Mutez
mbFee AppliedResult
ar Bool
isFirst = do
      let gasSafetyGuard :: StringEncode Int64
gasSafetyGuard = StringEncode Int64
100
          -- @gasSafetyGuard@ is added to origination operations and transfers to non-implicit
          -- accounts, see https://gitlab.com/tezos/tezos/-/blob/v13.0/src/proto_013_PtJakart/lib_client/injection.ml#L750
          additionalGas :: StringEncode Int64
additionalGas = case OperationInfo RPCInput
internalOp of
            OpOriginate OriginationInfo RPCInput
_ -> StringEncode Int64
gasSafetyGuard
            OpTransfer (TransactionOperation {Address
TezosMutez
ParametersInternal
toParameters :: ParametersInternal
toDestination :: Address
toAmount :: TezosMutez
toParameters :: TransactionOperation -> ParametersInternal
toAmount :: TransactionOperation -> TezosMutez
toDestination :: TransactionOperation -> Address
..}) -> case Address
toDestination of
              MkAddress ImplicitAddress{} -> StringEncode Int64
0
              MkAddress ContractAddress{} -> StringEncode Int64
gasSafetyGuard
              MkAddress TxRollupAddress{} -> StringEncode Int64
gasSafetyGuard
            OpReveal RevealInfo RPCInput
_ -> StringEncode Int64
0
            OpDelegation DelegationInfo RPCInput
_ -> StringEncode Int64
0
      let storageLimit :: StringEncode Int64
storageLimit = [AppliedResult] -> ProtocolParameters -> StringEncode Int64
computeStorageLimit [AppliedResult
ar] ProtocolParameters
pp StringEncode Int64 -> StringEncode Int64 -> StringEncode Int64
forall a. Num a => a -> a -> a
+ StringEncode Int64
20
          -- similarly to @octez-client@, we add 20 for safety
      let gasLimit :: StringEncode Int64
gasLimit = Ratio (StringEncode Int64) -> StringEncode Int64
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (AppliedResult -> StringEncode Int64
arConsumedMilliGas AppliedResult
ar StringEncode Int64
-> StringEncode Int64 -> Ratio (StringEncode Int64)
forall a. Integral a => a -> a -> Ratio a
% StringEncode Int64
1000) StringEncode Int64 -> StringEncode Int64 -> StringEncode Int64
forall a. Num a => a -> a -> a
+ StringEncode Int64
additionalGas
          updateCommonDataForFee :: Mutez -> CommonOperationData -> CommonOperationData
updateCommonDataForFee Mutez
fee =
            StringEncode Int64
-> StringEncode Int64
-> TezosMutez
-> CommonOperationData
-> CommonOperationData
updateCommonData StringEncode Int64
gasLimit StringEncode Int64
storageLimit (Mutez -> TezosMutez
TezosMutez Mutez
fee)

      (Mutez
_fee, WithCommonOperationData (OperationInfo RPCInput)
op, Maybe (Signature, ByteString)
mReadySignedOp) <- forall op extra (m :: * -> *).
Monad m =>
(Mutez -> m op) -> (op -> m (Mutez, extra)) -> m (Mutez, op, extra)
convergingFee
        @OperationInput
        @(Maybe (Signature, ByteString))  -- ready operation and its signature
        (\Mutez
fee ->
          WithCommonOperationData (OperationInfo RPCInput)
-> m (WithCommonOperationData (OperationInfo RPCInput))
forall (m :: * -> *) a. Monad m => a -> m a
return (WithCommonOperationData (OperationInfo RPCInput)
 -> m (WithCommonOperationData (OperationInfo RPCInput)))
-> WithCommonOperationData (OperationInfo RPCInput)
-> m (WithCommonOperationData (OperationInfo RPCInput))
forall a b. (a -> b) -> a -> b
$ WithCommonOperationData (OperationInfo RPCInput)
opToRun WithCommonOperationData (OperationInfo RPCInput)
-> State (WithCommonOperationData (OperationInfo RPCInput)) ()
-> WithCommonOperationData (OperationInfo RPCInput)
forall s a. s -> State s a -> s
&~
            (CommonOperationData -> Identity CommonOperationData)
-> WithCommonOperationData (OperationInfo RPCInput)
-> Identity (WithCommonOperationData (OperationInfo RPCInput))
forall a. Lens' (WithCommonOperationData a) CommonOperationData
wcoCommonDataL ((CommonOperationData -> Identity CommonOperationData)
 -> WithCommonOperationData (OperationInfo RPCInput)
 -> Identity (WithCommonOperationData (OperationInfo RPCInput)))
-> (CommonOperationData -> CommonOperationData)
-> State (WithCommonOperationData (OperationInfo RPCInput)) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Mutez -> CommonOperationData -> CommonOperationData
updateCommonDataForFee Mutez
fee
          )
        (\WithCommonOperationData (OperationInfo RPCInput)
op -> do
          ByteString
forgedOp <- NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
-> m ByteString
forgeOp (NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
 -> m ByteString)
-> NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
-> m ByteString
forall a b. (a -> b) -> a -> b
$ OneItem
  (NonEmpty (WithCommonOperationData (OperationInfo RPCInput)))
-> NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
forall x. One x => OneItem x -> x
one OneItem
  (NonEmpty (WithCommonOperationData (OperationInfo RPCInput)))
WithCommonOperationData (OperationInfo RPCInput)
op
          -- In the Tezos implementation the first transaction
          -- in the series pays for signature.
          -- Signature of hash should be constant in size,
          -- so we can pass any signature, not necessarily the final one
          (Int
fullForgedOpLength, Maybe (Signature, ByteString)
mExtra) <-
            if Bool
isFirst
              then do
                res :: (Signature, ByteString)
res@(Signature
_signature, ByteString
signedOp) <- ByteString -> m (Signature, ByteString)
signForgedOp ByteString
forgedOp
                (Int, Maybe (Signature, ByteString))
-> m (Int, Maybe (Signature, ByteString))
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> Int
forall t. Container t => t -> Int
length ByteString
signedOp, (Signature, ByteString) -> Maybe (Signature, ByteString)
forall a. a -> Maybe a
Just (Signature, ByteString)
res)
              else
                -- Forge output automatically includes additional 32-bytes header
                -- which should be ommited for all operations in batch except the first one.
                (Int, Maybe (Signature, ByteString))
-> m (Int, Maybe (Signature, ByteString))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> Int
forall t. Container t => t -> Int
length ByteString
forgedOp Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
32, Maybe (Signature, ByteString)
forall a. Maybe a
Nothing)
          (Mutez, Maybe (Signature, ByteString))
-> m (Mutez, Maybe (Signature, ByteString))
forall (m :: * -> *) a. Monad m => a -> m a
return
            ( Mutez -> (Mutez -> Mutez) -> Maybe Mutez -> Mutez
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (FeeConstants -> Int -> StringEncode Int64 -> Mutez
computeFee FeeConstants
ocFeeConstants Int
fullForgedOpLength StringEncode Int64
gasLimit) Mutez -> Mutez
forall a. a -> a
id Maybe Mutez
mbFee
            , Maybe (Signature, ByteString)
mExtra
            )
          )

      (WithCommonOperationData (OperationInfo RPCInput),
 Maybe (Signature, ByteString))
-> m (WithCommonOperationData (OperationInfo RPCInput),
      Maybe (Signature, ByteString))
forall (m :: * -> *) a. Monad m => a -> m a
return (WithCommonOperationData (OperationInfo RPCInput)
op, Maybe (Signature, ByteString)
mReadySignedOp)

  let
    zipWith4NE
      :: (a -> b -> c -> d -> e) -> NonEmpty a -> NonEmpty b -> NonEmpty c -> NonEmpty d
      -> NonEmpty e
    zipWith4NE :: forall a b c d e.
(a -> b -> c -> d -> e)
-> NonEmpty a
-> NonEmpty b
-> NonEmpty c
-> NonEmpty d
-> NonEmpty e
zipWith4NE a -> b -> c -> d -> e
f (a
a :| [a]
as) (b
b :| [b]
bs) (c
c :| [c]
cs) (d
d :| [d]
ds) =
      (a -> b -> c -> d -> e
f a
a b
b c
c d
d) e -> [e] -> NonEmpty e
forall a. a -> [a] -> NonEmpty a
:| (a -> b -> c -> d -> e) -> [a] -> [b] -> [c] -> [d] -> [e]
forall a b c d e.
(a -> b -> c -> d -> e) -> [a] -> [b] -> [c] -> [d] -> [e]
zipWith4 a -> b -> c -> d -> e
f [a]
as [b]
bs [c]
cs [d]
ds
  -- These two lists must have the same length here.
  -- @opsToRun@ is constructed directly from @params@.
  -- The length of @results@ is checked in @getAppliedResults@.
  (NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
updOps, NonEmpty (Maybe (Signature, ByteString))
readySignedOps) <- (NonEmpty
   (WithCommonOperationData (OperationInfo RPCInput),
    Maybe (Signature, ByteString))
 -> (NonEmpty (WithCommonOperationData (OperationInfo RPCInput)),
     NonEmpty (Maybe (Signature, ByteString))))
-> m (NonEmpty
        (WithCommonOperationData (OperationInfo RPCInput),
         Maybe (Signature, ByteString)))
-> m (NonEmpty (WithCommonOperationData (OperationInfo RPCInput)),
      NonEmpty (Maybe (Signature, ByteString)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap NonEmpty
  (WithCommonOperationData (OperationInfo RPCInput),
   Maybe (Signature, ByteString))
-> (NonEmpty (WithCommonOperationData (OperationInfo RPCInput)),
    NonEmpty (Maybe (Signature, ByteString)))
forall (f :: * -> *) a b. Functor f => f (a, b) -> (f a, f b)
NE.unzip (m (NonEmpty
      (WithCommonOperationData (OperationInfo RPCInput),
       Maybe (Signature, ByteString)))
 -> m (NonEmpty (WithCommonOperationData (OperationInfo RPCInput)),
       NonEmpty (Maybe (Signature, ByteString))))
-> (NonEmpty
      (m (WithCommonOperationData (OperationInfo RPCInput),
          Maybe (Signature, ByteString)))
    -> m (NonEmpty
            (WithCommonOperationData (OperationInfo RPCInput),
             Maybe (Signature, ByteString))))
-> NonEmpty
     (m (WithCommonOperationData (OperationInfo RPCInput),
         Maybe (Signature, ByteString)))
-> m (NonEmpty (WithCommonOperationData (OperationInfo RPCInput)),
      NonEmpty (Maybe (Signature, ByteString)))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty
  (m (WithCommonOperationData (OperationInfo RPCInput),
      Maybe (Signature, ByteString)))
-> m (NonEmpty
        (WithCommonOperationData (OperationInfo RPCInput),
         Maybe (Signature, ByteString)))
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
sequenceA (NonEmpty
   (m (WithCommonOperationData (OperationInfo RPCInput),
       Maybe (Signature, ByteString)))
 -> m (NonEmpty (WithCommonOperationData (OperationInfo RPCInput)),
       NonEmpty (Maybe (Signature, ByteString))))
-> NonEmpty
     (m (WithCommonOperationData (OperationInfo RPCInput),
         Maybe (Signature, ByteString)))
-> m (NonEmpty (WithCommonOperationData (OperationInfo RPCInput)),
      NonEmpty (Maybe (Signature, ByteString)))
forall a b. (a -> b) -> a -> b
$
    (WithCommonOperationData (OperationInfo RPCInput)
 -> Maybe Mutez
 -> AppliedResult
 -> Bool
 -> m (WithCommonOperationData (OperationInfo RPCInput),
       Maybe (Signature, ByteString)))
-> NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
-> NonEmpty (Maybe Mutez)
-> NonEmpty AppliedResult
-> NonEmpty Bool
-> NonEmpty
     (m (WithCommonOperationData (OperationInfo RPCInput),
         Maybe (Signature, ByteString)))
forall a b c d e.
(a -> b -> c -> d -> e)
-> NonEmpty a
-> NonEmpty b
-> NonEmpty c
-> NonEmpty d
-> NonEmpty e
zipWith4NE WithCommonOperationData (OperationInfo RPCInput)
-> Maybe Mutez
-> AppliedResult
-> Bool
-> m (WithCommonOperationData (OperationInfo RPCInput),
      Maybe (Signature, ByteString))
updateOp NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
opsToRun NonEmpty (Maybe Mutez)
mbFees NonEmpty AppliedResult
results (Bool
True Bool -> [Bool] -> NonEmpty Bool
forall a. a -> [a] -> NonEmpty a
:| Bool -> [Bool]
forall a. a -> [a]
repeat Bool
False)

  -- Forge operation with given limits and get its hexadecimal representation
  (Signature
signature', ByteString
signedOp) <- case NonEmpty (Maybe (Signature, ByteString))
readySignedOps of
    -- Save one forge + sign call pair in case of one operation
    Just (Signature, ByteString)
readyOp :| [] -> (Signature, ByteString) -> m (Signature, ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Signature, ByteString)
readyOp
    -- In case of batch we have to reforge the full operation
    NonEmpty (Maybe (Signature, ByteString))
_ -> NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
-> m ByteString
forgeOp NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
updOps m ByteString
-> (ByteString -> m (Signature, ByteString))
-> m (Signature, ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString -> m (Signature, ByteString)
signForgedOp

  -- Operation still can fail due to insufficient gas or storage limit, so it's required
  -- to preapply it before injecting
  let preApplyOp :: PreApplyOperation
preApplyOp = PreApplyOperation :: Text
-> BlockHash
-> NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
-> Signature
-> PreApplyOperation
PreApplyOperation
        { paoProtocol :: Text
paoProtocol = BlockConstants -> Text
bcProtocol BlockConstants
ocBlockConstants
        , paoBranch :: BlockHash
paoBranch = BlockHash
ocLastBlockHash
        , paoContents :: NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
paoContents = NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
updOps
        , paoSignature :: Signature
paoSignature = Signature
signature'
        }
  (NonEmpty AppliedResult
ars2, [InternalOperationData]
iopsData) <- Either RunOperation PreApplyOperation
-> m (NonEmpty AppliedResult, [InternalOperationData])
forall (m :: * -> *).
HasTezosRpc m =>
Either RunOperation PreApplyOperation
-> m (NonEmpty AppliedResult, [InternalOperationData])
getAppliedResults (PreApplyOperation -> Either RunOperation PreApplyOperation
forall a b. b -> Either a b
Right PreApplyOperation
preApplyOp)
  case forall {k} (a :: k). SingI a => Sing a
forall (a :: RunMode). SingI a => Sing a
sing @runMode of
    Sing runMode
SingRunResult runMode
SDryRun -> do
      let fees :: NonEmpty TezosMutez
fees = (WithCommonOperationData (OperationInfo RPCInput) -> TezosMutez)
-> NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
-> NonEmpty TezosMutez
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (CommonOperationData -> TezosMutez
codFee (CommonOperationData -> TezosMutez)
-> (WithCommonOperationData (OperationInfo RPCInput)
    -> CommonOperationData)
-> WithCommonOperationData (OperationInfo RPCInput)
-> TezosMutez
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WithCommonOperationData (OperationInfo RPCInput)
-> CommonOperationData
forall a. WithCommonOperationData a -> CommonOperationData
wcoCommon) NonEmpty (WithCommonOperationData (OperationInfo RPCInput))
updOps
      NonEmpty (AppliedResult, TezosMutez)
-> m (NonEmpty (AppliedResult, TezosMutez))
forall (m :: * -> *) a. Monad m => a -> m a
return (NonEmpty (AppliedResult, TezosMutez)
 -> m (NonEmpty (AppliedResult, TezosMutez)))
-> NonEmpty (AppliedResult, TezosMutez)
-> m (NonEmpty (AppliedResult, TezosMutez))
forall a b. (a -> b) -> a -> b
$ NonEmpty AppliedResult
-> NonEmpty TezosMutez -> NonEmpty (AppliedResult, TezosMutez)
forall a b. NonEmpty a -> NonEmpty b -> NonEmpty (a, b)
NE.zip NonEmpty AppliedResult
ars2 NonEmpty TezosMutez
fees
    Sing runMode
SingRunResult runMode
SRealRun -> do
      OperationHash
operationHash <- m OperationHash -> m OperationHash
forall (m :: * -> *).
HasTezosRpc m =>
m OperationHash -> m OperationHash
waitForOperation (m OperationHash -> m OperationHash)
-> m OperationHash -> m OperationHash
forall a b. (a -> b) -> a -> b
$ HexJSONByteString -> m OperationHash
forall (m :: * -> *).
HasTezosRpc m =>
HexJSONByteString -> m OperationHash
injectOperation (ByteString -> HexJSONByteString
HexJSONByteString ByteString
signedOp)
      let contractAddrs :: NonEmpty [KindedAddress 'AddressKindContract]
contractAddrs = AppliedResult -> [KindedAddress 'AddressKindContract]
arOriginatedContracts (AppliedResult -> [KindedAddress 'AddressKindContract])
-> NonEmpty AppliedResult
-> NonEmpty [KindedAddress 'AddressKindContract]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty AppliedResult
ars2
      NonEmpty (OperationInfo Result)
opsRes <- NonEmpty
  (OperationInfo ClientInput, [KindedAddress 'AddressKindContract])
-> ((OperationInfo ClientInput,
     [KindedAddress 'AddressKindContract])
    -> m (OperationInfo Result))
-> m (NonEmpty (OperationInfo Result))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM (NonEmpty (OperationInfo ClientInput)
-> NonEmpty [KindedAddress 'AddressKindContract]
-> NonEmpty
     (OperationInfo ClientInput, [KindedAddress 'AddressKindContract])
forall a b. NonEmpty a -> NonEmpty b -> NonEmpty (a, b)
NE.zip NonEmpty (OperationInfo ClientInput)
operations NonEmpty [KindedAddress 'AddressKindContract]
contractAddrs) (((OperationInfo ClientInput, [KindedAddress 'AddressKindContract])
  -> m (OperationInfo Result))
 -> m (NonEmpty (OperationInfo Result)))
-> ((OperationInfo ClientInput,
     [KindedAddress 'AddressKindContract])
    -> m (OperationInfo Result))
-> m (NonEmpty (OperationInfo Result))
forall a b. (a -> b) -> a -> b
$ \case
        (OpTransfer TransferInfo ClientInput
_, []) ->
          OperationInfo Result -> m (OperationInfo Result)
forall (m :: * -> *) a. Monad m => a -> m a
return (OperationInfo Result -> m (OperationInfo Result))
-> OperationInfo Result -> m (OperationInfo Result)
forall a b. (a -> b) -> a -> b
$ TransferInfo Result -> OperationInfo Result
forall i. TransferInfo i -> OperationInfo i
OpTransfer (TransferInfo Result -> OperationInfo Result)
-> TransferInfo Result -> OperationInfo Result
forall a b. (a -> b) -> a -> b
$ (InternalOperationData -> Maybe IntOpEvent)
-> [InternalOperationData] -> [IntOpEvent]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe InternalOperationData -> Maybe IntOpEvent
iopsDataToEmitOp [InternalOperationData]
iopsData
        (OpTransfer TransferInfo ClientInput
_, [KindedAddress 'AddressKindContract]
addrs) -> do
          Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logInfo (Text -> m ()) -> (Text -> Text) -> Text -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.strip (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
            Builder
"The following contracts were originated during transactions: " Builder -> Builder -> Text
forall b. FromBuilder b => Builder -> Builder -> b
+|
            [KindedAddress 'AddressKindContract] -> Builder
forall (f :: * -> *) a. (Foldable f, Buildable a) => f a -> Builder
listF [KindedAddress 'AddressKindContract]
addrs Builder -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
""
          return $ TransferInfo Result -> OperationInfo Result
forall i. TransferInfo i -> OperationInfo i
OpTransfer (TransferInfo Result -> OperationInfo Result)
-> TransferInfo Result -> OperationInfo Result
forall a b. (a -> b) -> a -> b
$ (InternalOperationData -> Maybe IntOpEvent)
-> [InternalOperationData] -> [IntOpEvent]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe InternalOperationData -> Maybe IntOpEvent
iopsDataToEmitOp [InternalOperationData]
iopsData
        (OpOriginate OriginationInfo ClientInput
_, []) ->
          IncorrectRpcResponse -> m (OperationInfo Result)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM IncorrectRpcResponse
RpcOriginatedNoContracts
        (OpOriginate OriginationData{Maybe KeyHash
Maybe Mutez
ContractAlias
AliasBehavior
Mutez
Contract cp st
Value st
odMbFee :: Maybe Mutez
odDelegate :: Maybe KeyHash
odStorage :: Value st
odContract :: Contract cp st
odBalance :: Mutez
odName :: ContractAlias
odAliasBehavior :: AliasBehavior
odMbFee :: OriginationData -> Maybe Mutez
odDelegate :: OriginationData -> Maybe KeyHash
odStorage :: ()
odContract :: ()
odBalance :: OriginationData -> Mutez
odAliasBehavior :: OriginationData -> AliasBehavior
odName :: OriginationData -> ContractAlias
..}, [KindedAddress 'AddressKindContract
addr]) -> do
          Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logDebug (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ Builder
"Saving " Builder -> Builder -> Text
forall b. FromBuilder b => Builder -> Builder -> b
+| KindedAddress 'AddressKindContract
addr KindedAddress 'AddressKindContract -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
" for " Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+| ContractAlias
odName ContractAlias -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
"\n"
          AliasBehavior
-> KindedAddress 'AddressKindContract -> ContractAlias -> m ()
forall (m :: * -> *).
HasTezosClient m =>
AliasBehavior
-> KindedAddress 'AddressKindContract -> ContractAlias -> m ()
rememberContract AliasBehavior
odAliasBehavior KindedAddress 'AddressKindContract
addr ContractAlias
odName
          Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logInfo (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ Text
"Originated contract: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ContractAlias -> Text
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty ContractAlias
odName
          return $ OriginationInfo Result -> OperationInfo Result
forall i. OriginationInfo i -> OperationInfo i
OpOriginate KindedAddress 'AddressKindContract
OriginationInfo Result
addr
        (OpOriginate OriginationInfo ClientInput
_, addrs :: [KindedAddress 'AddressKindContract]
addrs@(KindedAddress 'AddressKindContract
_ : KindedAddress 'AddressKindContract
_ : [KindedAddress 'AddressKindContract]
_)) ->
          IncorrectRpcResponse -> m (OperationInfo Result)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (IncorrectRpcResponse -> m (OperationInfo Result))
-> IncorrectRpcResponse -> m (OperationInfo Result)
forall a b. (a -> b) -> a -> b
$ [KindedAddress 'AddressKindContract] -> IncorrectRpcResponse
RpcOriginatedMoreContracts [KindedAddress 'AddressKindContract]
addrs
        (OpReveal RevealInfo ClientInput
_, [KindedAddress 'AddressKindContract]
_) ->
          OperationInfo Result -> m (OperationInfo Result)
forall (m :: * -> *) a. Monad m => a -> m a
return (OperationInfo Result -> m (OperationInfo Result))
-> OperationInfo Result -> m (OperationInfo Result)
forall a b. (a -> b) -> a -> b
$ RevealInfo Result -> OperationInfo Result
forall i. RevealInfo i -> OperationInfo i
OpReveal ()
        (OpDelegation DelegationInfo ClientInput
_, [KindedAddress 'AddressKindContract]
_) ->
          OperationInfo Result -> m (OperationInfo Result)
forall (m :: * -> *) a. Monad m => a -> m a
return (OperationInfo Result -> m (OperationInfo Result))
-> OperationInfo Result -> m (OperationInfo Result)
forall a b. (a -> b) -> a -> b
$ DelegationInfo Result -> OperationInfo Result
forall i. DelegationInfo i -> OperationInfo i
OpDelegation ()
      NonEmpty AppliedResult
-> (Element (NonEmpty AppliedResult) -> m ()) -> m ()
forall t (m :: * -> *) b.
(Container t, Monad m) =>
t -> (Element t -> m b) -> m ()
forM_ NonEmpty AppliedResult
ars2 Element (NonEmpty AppliedResult) -> m ()
AppliedResult -> m ()
logStatistics
      return (OperationHash
operationHash, NonEmpty (OperationInfo Result)
opsRes)
      m (OperationHash, NonEmpty (OperationInfo Result))
-> (UnexpectedErrors
    -> m (OperationHash, NonEmpty (OperationInfo Result)))
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`catch` \case
        (UnexpectedRunErrors [RunError]
errs) | Natural
retryCount Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
> Natural
0 -> do
          Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logError (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ Builder -> Text
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty (Builder -> Text) -> Builder -> Text
forall a b. (a -> b) -> a -> b
$ Builder -> Builder -> Builder
nameF Builder
"When injecting operations, there were unexpected errors" (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$
            [RunError] -> Builder
forall (f :: * -> *) a. (Foldable f, Buildable a) => f a -> Builder
blockListF [RunError]
errs
          forall (runMode :: RunMode) (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 SingI runMode) =>
Natural
-> AddressOrAlias 'AddressKindImplicit
-> NonEmpty (OperationInfo ClientInput)
-> m (RunResult runMode)
runOperationsNonEmptyHelper @runMode (Natural
retryCount Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
1) AddressOrAlias 'AddressKindImplicit
sender NonEmpty (OperationInfo ClientInput)
operations
        UnexpectedErrors
e -> UnexpectedErrors
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM UnexpectedErrors
e
  where
    iopsDataToEmitOp :: InternalOperationData -> Maybe IntOpEvent
    iopsDataToEmitOp :: InternalOperationData -> Maybe IntOpEvent
iopsDataToEmitOp = \case
      IODEvent IntOpEvent
evt -> IntOpEvent -> Maybe IntOpEvent
forall a. a -> Maybe a
Just IntOpEvent
evt
      InternalOperationData
_ -> Maybe IntOpEvent
forall a. Maybe a
Nothing

    mayNeedSenderRevealing :: [OperationInfo i] -> Bool
    mayNeedSenderRevealing :: forall i. [OperationInfo i] -> Bool
mayNeedSenderRevealing = (Element [OperationInfo i] -> Bool) -> [OperationInfo i] -> Bool
forall t. Container t => (Element t -> Bool) -> t -> Bool
any \case
      OpTransfer{} -> Bool
True
      OpOriginate{} -> Bool
True
      OpReveal{} -> Bool
False
      OpDelegation{} -> Bool
True

    logStatistics :: AppliedResult -> m ()
    logStatistics :: AppliedResult -> m ()
logStatistics AppliedResult
ar = do
      let showTezosInt64 :: StringEncode Int64 -> Text
showTezosInt64 = Int64 -> Text
forall b a. (PrettyShow a, Show a, IsString b) => a -> b
show (Int64 -> Text)
-> (StringEncode Int64 -> Int64) -> StringEncode Int64 -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StringEncode Int64 -> Int64
forall a. StringEncode a -> a
unStringEncode
      Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logInfo (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ Text
"Consumed milli-gas: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> StringEncode Int64 -> Text
showTezosInt64 (AppliedResult -> StringEncode Int64
arConsumedMilliGas AppliedResult
ar)
      Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logInfo (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ Text
"Storage size: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> StringEncode Int64 -> Text
showTezosInt64 (AppliedResult -> StringEncode Int64
arStorageSize AppliedResult
ar)
      Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logInfo (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ Text
"Paid storage size diff: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> StringEncode Int64 -> Text
showTezosInt64 (AppliedResult -> StringEncode Int64
arPaidStorageDiff AppliedResult
ar)