-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ

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

import Data.List (zipWith4)
import qualified Data.List.NonEmpty as NE
import Data.Singletons (Sing, SingI, sing)
import qualified Data.Text as T
import Fmt (blockListF', listF, 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.Micheline (StringEncode(..), TezosInt64, TezosMutez(..))
import Morley.Tezos.Address
import Morley.Tezos.Crypto
import Morley.Util.ByteString

logOperations
  :: forall (runMode :: RunMode) env m.
     ( WithClientLog env m
     , HasTezosClient m
     , SingI runMode -- We don't ask aliases with 'tezos-client' in 'DryRun' mode
     )
  => AddressOrAlias
  -> NonEmpty (Either TransactionData OriginationData)
  -> m ()
logOperations :: AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData) -> m ()
logOperations AddressOrAlias
sender NonEmpty (Either TransactionData OriginationData)
ops = do
  let runMode :: Sing runMode
runMode = SingI runMode => Sing runMode
forall k (a :: k). SingI a => Sing a
sing @runMode

      opName :: Builder
opName =
        if | (Element (NonEmpty (Either TransactionData OriginationData))
 -> Bool)
-> NonEmpty (Either TransactionData OriginationData) -> Bool
forall t. Container t => (Element t -> Bool) -> t -> Bool
all Element (NonEmpty (Either TransactionData OriginationData)) -> Bool
forall a b. Either a b -> Bool
isLeft NonEmpty (Either TransactionData OriginationData)
ops -> Builder
"transactions"
           | (Element (NonEmpty (Either TransactionData OriginationData))
 -> Bool)
-> NonEmpty (Either TransactionData OriginationData) -> Bool
forall t. Container t => (Element t -> Bool) -> t -> Bool
all Element (NonEmpty (Either TransactionData OriginationData)) -> Bool
forall a b. Either a b -> Bool
isRight NonEmpty (Either TransactionData OriginationData)
ops -> Builder
"originations"
           | Bool
otherwise -> Builder
"operations"

      buildOp :: (Either TransactionData OriginationData, Maybe Alias) -> Builder
buildOp = \case
        (Left TransactionData
tx, Maybe Alias
mbAlias) ->
          Maybe Alias -> TransactionData -> Builder
buildTxDataWithAlias Maybe Alias
mbAlias TransactionData
tx
        (Right OriginationData
orig, Maybe Alias
_) ->
          OriginationData -> AliasHint
odName OriginationData
orig AliasHint -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
" (temporary alias)"

  AddressOrAlias
sender' <- case AddressOrAlias
sender of
    addr :: AddressOrAlias
addr@AddressResolved{} -> case Sing runMode
runMode of
      Sing runMode
SRealRun -> Alias -> AddressOrAlias
AddressAlias (Alias -> AddressOrAlias) -> m Alias -> m AddressOrAlias
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AddressOrAlias -> m Alias
forall (m :: * -> *). HasTezosClient m => AddressOrAlias -> m Alias
getAlias AddressOrAlias
sender
      Sing runMode
SDryRun  -> AddressOrAlias -> m AddressOrAlias
forall (f :: * -> *) a. Applicative f => a -> f a
pure AddressOrAlias
addr
    AddressOrAlias
alias -> AddressOrAlias -> m AddressOrAlias
forall (f :: * -> *) a. Applicative f => a -> f a
pure AddressOrAlias
alias

  NonEmpty (Maybe Alias)
aliases <- case Sing runMode
runMode of
    Sing runMode
SRealRun ->
      NonEmpty (Either TransactionData OriginationData)
-> (Either TransactionData OriginationData -> m (Maybe Alias))
-> m (NonEmpty (Maybe Alias))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM NonEmpty (Either TransactionData OriginationData)
ops ((Either TransactionData OriginationData -> m (Maybe Alias))
 -> m (NonEmpty (Maybe Alias)))
-> (Either TransactionData OriginationData -> m (Maybe Alias))
-> m (NonEmpty (Maybe Alias))
forall a b. (a -> b) -> a -> b
$ \case
        Left (TransactionData TD (Value t)
tx) ->
          Alias -> Maybe Alias
forall a. a -> Maybe a
Just (Alias -> Maybe Alias) -> m Alias -> m (Maybe Alias)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (AddressOrAlias -> m Alias
forall (m :: * -> *). HasTezosClient m => AddressOrAlias -> m Alias
getAlias (AddressOrAlias -> m Alias)
-> (Address -> AddressOrAlias) -> Address -> m Alias
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Address -> AddressOrAlias
AddressResolved (Address -> m Alias) -> Address -> m Alias
forall a b. (a -> b) -> a -> b
$ TD (Value t) -> Address
forall t. TD t -> Address
tdReceiver TD (Value t)
tx)
        Either TransactionData OriginationData
_ ->
          Maybe Alias -> m (Maybe Alias)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Alias
forall a. Maybe a
Nothing
    Sing runMode
SDryRun -> NonEmpty (Maybe Alias) -> m (NonEmpty (Maybe Alias))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (NonEmpty (Maybe Alias) -> m (NonEmpty (Maybe Alias)))
-> NonEmpty (Maybe Alias) -> m (NonEmpty (Maybe Alias))
forall a b. (a -> b) -> a -> b
$ NonEmpty (Either TransactionData OriginationData)
ops NonEmpty (Either TransactionData OriginationData)
-> Maybe Alias -> NonEmpty (Maybe Alias)
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> Maybe Alias
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
sender' AddressOrAlias -> 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
-> ((Either TransactionData OriginationData, Maybe Alias)
    -> Builder)
-> NonEmpty (Either TransactionData OriginationData, Maybe Alias)
-> Builder
forall (f :: * -> *) a.
Foldable f =>
Text -> (a -> Builder) -> f a -> Builder
blockListF' Text
"-" (Either TransactionData OriginationData, Maybe Alias) -> Builder
buildOp (NonEmpty (Either TransactionData OriginationData)
ops NonEmpty (Either TransactionData OriginationData)
-> NonEmpty (Maybe Alias)
-> NonEmpty (Either TransactionData OriginationData, Maybe Alias)
forall a b. NonEmpty a -> NonEmpty b -> NonEmpty (a, b)
`NE.zip` NonEmpty (Maybe Alias)
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
     )
  => AddressOrAlias
  -> [Either TransactionData OriginationData]
  -> m (Maybe OperationHash, [Either () Address])
runOperations :: AddressOrAlias
-> [Either TransactionData OriginationData]
-> m (Maybe OperationHash, [Either () Address])
runOperations AddressOrAlias
sender [Either TransactionData OriginationData]
operations = case [Either TransactionData OriginationData]
operations of
  [] -> (Maybe OperationHash, [Either () Address])
-> m (Maybe OperationHash, [Either () Address])
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe OperationHash
forall a. Maybe a
Nothing, [])
  Either TransactionData OriginationData
op : [Either TransactionData OriginationData]
ops -> do
    (OperationHash
opHash, NonEmpty (Either () Address)
res) <- AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData)
-> m (OperationHash, NonEmpty (Either () Address))
forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData)
-> m (OperationHash, NonEmpty (Either () Address))
runOperationsNonEmpty AddressOrAlias
sender (NonEmpty (Either TransactionData OriginationData)
 -> m (OperationHash, NonEmpty (Either () Address)))
-> NonEmpty (Either TransactionData OriginationData)
-> m (OperationHash, NonEmpty (Either () Address))
forall a b. (a -> b) -> a -> b
$ Either TransactionData OriginationData
op Either TransactionData OriginationData
-> [Either TransactionData OriginationData]
-> NonEmpty (Either TransactionData OriginationData)
forall a. a -> [a] -> NonEmpty a
:| [Either TransactionData OriginationData]
ops
    (Maybe OperationHash, [Either () Address])
-> m (Maybe OperationHash, [Either () Address])
forall (m :: * -> *) a. Monad m => a -> m a
return ((Maybe OperationHash, [Either () Address])
 -> m (Maybe OperationHash, [Either () Address]))
-> (Maybe OperationHash, [Either () Address])
-> m (Maybe OperationHash, [Either () Address])
forall a b. (a -> b) -> a -> b
$ (OperationHash -> Maybe OperationHash
forall a. a -> Maybe a
Just OperationHash
opHash, NonEmpty (Either () Address)
-> [Element (NonEmpty (Either () Address))]
forall t. Container t => t -> [Element t]
toList NonEmpty (Either () Address)
res)

-- | 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
     )
  => AddressOrAlias
  -> NonEmpty (Either TransactionData OriginationData)
  -> m (OperationHash, NonEmpty (Either () Address))
runOperationsNonEmpty :: AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData)
-> m (OperationHash, NonEmpty (Either () Address))
runOperationsNonEmpty AddressOrAlias
sender NonEmpty (Either TransactionData OriginationData)
operations =
  AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData)
-> m (RunResult 'RealRun)
forall (runMode :: RunMode) (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 SingI runMode) =>
AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData)
-> m (RunResult runMode)
runOperationsNonEmptyHelper @'RealRun AddressOrAlias
sender NonEmpty (Either TransactionData OriginationData)
operations

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

isRealRun :: forall (runMode :: RunMode). (SingI runMode) => Bool
isRealRun :: Bool
isRealRun = case SingI runMode => Sing runMode
forall k (a :: k). SingI a => Sing a
sing @runMode of
  Sing runMode
SRealRun -> Bool
True
  Sing 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 (Either () Address))

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
     )
  => AddressOrAlias
  -> NonEmpty (Either TransactionData OriginationData)
  -> m (NonEmpty (AppliedResult, TezosMutez))
dryRunOperationsNonEmpty :: AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData)
-> m (NonEmpty (AppliedResult, TezosMutez))
dryRunOperationsNonEmpty AddressOrAlias
sender NonEmpty (Either TransactionData OriginationData)
operations =
  AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData)
-> m (RunResult 'DryRun)
forall (runMode :: RunMode) (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 SingI runMode) =>
AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData)
-> m (RunResult runMode)
runOperationsNonEmptyHelper @'DryRun AddressOrAlias
sender NonEmpty (Either TransactionData OriginationData)
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
     )
  => AddressOrAlias
  -> NonEmpty (Either TransactionData OriginationData)
  -> m (RunResult runMode)
runOperationsNonEmptyHelper :: AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData)
-> m (RunResult runMode)
runOperationsNonEmptyHelper AddressOrAlias
sender NonEmpty (Either TransactionData OriginationData)
operations = do
  AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData) -> m ()
forall (runMode :: RunMode) env (m :: * -> *).
(WithClientLog env m, HasTezosClient m, SingI runMode) =>
AddressOrAlias
-> NonEmpty (Either TransactionData OriginationData) -> m ()
logOperations @runMode AddressOrAlias
sender NonEmpty (Either TransactionData OriginationData)
operations
  Address
senderAddress <- AddressOrAlias -> m Address
forall (m :: * -> *).
(MonadThrow m, HasTezosClient m) =>
AddressOrAlias -> m Address
resolveAddress AddressOrAlias
sender
  Address -> Either TransactionData OriginationData -> m ()
prohibitContractSender Address
senderAddress (Either TransactionData OriginationData -> m ())
-> Either TransactionData OriginationData -> m ()
forall a b. (a -> b) -> a -> b
$ NonEmpty (Either TransactionData OriginationData)
-> Either TransactionData OriginationData
forall a. NonEmpty a -> a
head NonEmpty (Either TransactionData OriginationData)
operations
  Maybe ScrubbedBytes
mbPassword <- Address -> m (Maybe ScrubbedBytes)
forall (m :: * -> *).
HasTezosClient m =>
Address -> m (Maybe ScrubbedBytes)
getKeyPassword Address
senderAddress
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (SingI runMode => Bool
forall (runMode :: RunMode). SingI runMode => Bool
isRealRun @runMode) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
    Address -> Maybe ScrubbedBytes -> m ()
forall env (m :: * -> *).
(WithClientLog env m, HasTezosRpc m, HasTezosClient m) =>
Address -> Maybe ScrubbedBytes -> m ()
revealKeyUnlessRevealed Address
senderAddress Maybe ScrubbedBytes
mbPassword

  ProtocolParameters
pp <- m ProtocolParameters
forall (m :: * -> *). HasTezosRpc m => m ProtocolParameters
getProtocolParameters
  OperationConstants{Text
TezosInt64
FeeConstants
BlockConstants
ocCounter :: OperationConstants -> TezosInt64
ocFeeConstants :: OperationConstants -> FeeConstants
ocBlockConstants :: OperationConstants -> BlockConstants
ocLastBlockHash :: OperationConstants -> Text
ocCounter :: TezosInt64
ocFeeConstants :: FeeConstants
ocBlockConstants :: BlockConstants
ocLastBlockHash :: Text
..} <- Address -> m OperationConstants
forall (m :: * -> *).
HasTezosRpc m =>
Address -> m OperationConstants
preProcessOperation Address
senderAddress

  let convertOps :: TezosInt64
-> Either TransactionData OriginationData
-> Either TransactionOperation OriginationOperation
convertOps TezosInt64
i = \case
        Left (TransactionData TD {Maybe Mutez
EpName
Address
Mutez
Value t
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
tdReceiver :: Address
tdReceiver :: forall t. TD t -> Address
..}) ->
          TransactionOperation
-> Either TransactionOperation OriginationOperation
forall a b. a -> Either a b
Left TransactionOperation :: CommonOperationData
-> TezosMutez
-> Address
-> ParametersInternal
-> TransactionOperation
TransactionOperation
          { toDestination :: Address
toDestination = Address
tdReceiver
          , toCommonData :: CommonOperationData
toCommonData = CommonOperationData
commonData
          , 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
          }
        Right OriginationData{Bool
Maybe Mutez
Mutez
Value st
Contract cp st
AliasHint
odMbFee :: OriginationData -> Maybe Mutez
odStorage :: ()
odContract :: ()
odBalance :: OriginationData -> Mutez
odReplaceExisting :: OriginationData -> Bool
odMbFee :: Maybe Mutez
odStorage :: Value st
odContract :: Contract cp st
odBalance :: Mutez
odName :: AliasHint
odReplaceExisting :: Bool
odName :: OriginationData -> AliasHint
..} ->
          OriginationOperation
-> Either TransactionOperation OriginationOperation
forall a b. b -> Either a b
Right OriginationOperation :: CommonOperationData
-> TezosMutez -> OriginationScript -> OriginationOperation
OriginationOperation
          { ooCommonData :: CommonOperationData
ooCommonData = CommonOperationData
commonData
          , ooBalance :: TezosMutez
ooBalance = Mutez -> TezosMutez
TezosMutez Mutez
odBalance
          , 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
          }
        where
          commonData :: CommonOperationData
commonData = Address -> TezosInt64 -> ProtocolParameters -> CommonOperationData
mkCommonOperationData Address
senderAddress (TezosInt64
ocCounter TezosInt64 -> TezosInt64 -> TezosInt64
forall a. Num a => a -> a -> a
+ TezosInt64
i) ProtocolParameters
pp

  let opsToRun :: NonEmpty (Either TransactionOperation OriginationOperation)
opsToRun = (TezosInt64
 -> Either TransactionData OriginationData
 -> Either TransactionOperation OriginationOperation)
-> NonEmpty TezosInt64
-> NonEmpty (Either TransactionData OriginationData)
-> NonEmpty (Either TransactionOperation OriginationOperation)
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NE.zipWith TezosInt64
-> Either TransactionData OriginationData
-> Either TransactionOperation OriginationOperation
convertOps (TezosInt64
1 TezosInt64 -> [TezosInt64] -> NonEmpty TezosInt64
forall a. a -> [a] -> NonEmpty a
:| [(TezosInt64
2 :: TezosInt64)..]) NonEmpty (Either TransactionData OriginationData)
operations
      mbFees :: NonEmpty (Maybe Mutez)
mbFees = (Either TransactionData OriginationData -> Maybe Mutez)
-> NonEmpty (Either TransactionData OriginationData)
-> NonEmpty (Maybe Mutez)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map ((TransactionData -> Maybe Mutez)
-> (OriginationData -> Maybe Mutez)
-> Either TransactionData OriginationData
-> Maybe Mutez
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (\(TransactionData TD {Maybe Mutez
EpName
Address
Mutez
Value t
tdMbFee :: Maybe Mutez
tdParam :: Value t
tdEpName :: EpName
tdAmount :: Mutez
tdReceiver :: Address
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 -> Address
..}) -> Maybe Mutez
tdMbFee) OriginationData -> Maybe Mutez
odMbFee) NonEmpty (Either TransactionData OriginationData)
operations

  -- 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 :: Text
-> NonEmpty (Either TransactionOperation OriginationOperation)
-> Signature
-> RunOperationInternal
RunOperationInternal
          { roiBranch :: Text
roiBranch = Text
ocLastBlockHash
          , roiContents :: NonEmpty (Either TransactionOperation OriginationOperation)
roiContents = NonEmpty (Either TransactionOperation OriginationOperation)
opsToRun
          , roiSignature :: Signature
roiSignature = Signature
stubSignature
          }
        , roChainId :: Text
roChainId = BlockConstants -> Text
bcChainId BlockConstants
ocBlockConstants
        }
  NonEmpty AppliedResult
results <- Either RunOperation PreApplyOperation -> m (NonEmpty AppliedResult)
forall (m :: * -> *).
HasTezosRpc m =>
Either RunOperation PreApplyOperation -> m (NonEmpty AppliedResult)
getAppliedResults (RunOperation -> Either RunOperation PreApplyOperation
forall a b. a -> Either a b
Left RunOperation
runOp)

  let -- Learn how to forge given operations
      forgeOp :: NonEmpty (Either TransactionOperation OriginationOperation) -> m ByteString
      forgeOp :: NonEmpty (Either TransactionOperation OriginationOperation)
-> m ByteString
forgeOp NonEmpty (Either TransactionOperation OriginationOperation)
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 :: Text
-> NonEmpty (Either TransactionOperation OriginationOperation)
-> ForgeOperation
ForgeOperation
          { foBranch :: Text
foBranch = Text
ocLastBlockHash
          , foContents :: NonEmpty (Either TransactionOperation OriginationOperation)
foContents = NonEmpty (Either TransactionOperation OriginationOperation)
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 -> Maybe ScrubbedBytes -> ByteString -> m Signature
forall (m :: * -> *).
HasTezosClient m =>
AddressOrAlias -> Maybe ScrubbedBytes -> ByteString -> m Signature
signBytes AddressOrAlias
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 :: Either TransactionOperation OriginationOperation
-> Maybe Mutez
-> AppliedResult
-> Bool
-> m (Either TransactionOperation OriginationOperation,
      Maybe (Signature, ByteString))
updateOp Either TransactionOperation OriginationOperation
opToRun Maybe Mutez
mbFee AppliedResult
ar Bool
isFirst = do
      let storageLimit :: TezosInt64
storageLimit = [AppliedResult] -> ProtocolParameters -> TezosInt64
computeStorageLimit [AppliedResult
ar] ProtocolParameters
pp TezosInt64 -> TezosInt64 -> TezosInt64
forall a. Num a => a -> a -> a
+ TezosInt64
20 -- similarly to tezos-client, we add 20 for safety
      let gasLimit :: TezosInt64
gasLimit = AppliedResult -> TezosInt64
arConsumedGas AppliedResult
ar TezosInt64 -> TezosInt64 -> TezosInt64
forall a. Num a => a -> a -> a
+ TezosInt64
100  -- adding extra for safety
          updateCommonDataForFee :: Mutez -> CommonOperationData -> CommonOperationData
updateCommonDataForFee Mutez
fee =
            TezosInt64
-> TezosInt64
-> TezosMutez
-> CommonOperationData
-> CommonOperationData
updateCommonData TezosInt64
gasLimit TezosInt64
storageLimit (Mutez -> TezosMutez
TezosMutez Mutez
fee)

      (Mutez
_fee, Either TransactionOperation OriginationOperation
op, Maybe (Signature, ByteString)
mReadySignedOp) <- (Mutez -> m (Either TransactionOperation OriginationOperation))
-> (Either TransactionOperation OriginationOperation
    -> m (Mutez, Maybe (Signature, ByteString)))
-> m (Mutez, Either TransactionOperation OriginationOperation,
      Maybe (Signature, ByteString))
forall op extra (m :: * -> *).
Monad m =>
(Mutez -> m op) -> (op -> m (Mutez, extra)) -> m (Mutez, op, extra)
convergingFee
        @(Either TransactionOperation OriginationOperation)
        @(Maybe (Signature, ByteString))  -- ready operation and its signature
        (\Mutez
fee ->
          Either TransactionOperation OriginationOperation
-> m (Either TransactionOperation OriginationOperation)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either TransactionOperation OriginationOperation
 -> m (Either TransactionOperation OriginationOperation))
-> Either TransactionOperation OriginationOperation
-> m (Either TransactionOperation OriginationOperation)
forall a b. (a -> b) -> a -> b
$ (TransactionOperation -> TransactionOperation)
-> (OriginationOperation -> OriginationOperation)
-> Either TransactionOperation OriginationOperation
-> Either TransactionOperation OriginationOperation
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap
            ((CommonOperationData -> Identity CommonOperationData)
-> TransactionOperation -> Identity TransactionOperation
Lens' TransactionOperation CommonOperationData
toCommonDataL ((CommonOperationData -> Identity CommonOperationData)
 -> TransactionOperation -> Identity TransactionOperation)
-> (CommonOperationData -> CommonOperationData)
-> TransactionOperation
-> TransactionOperation
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Mutez -> CommonOperationData -> CommonOperationData
updateCommonDataForFee Mutez
fee)
            ((CommonOperationData -> Identity CommonOperationData)
-> OriginationOperation -> Identity OriginationOperation
Lens' OriginationOperation CommonOperationData
ooCommonDataL ((CommonOperationData -> Identity CommonOperationData)
 -> OriginationOperation -> Identity OriginationOperation)
-> (CommonOperationData -> CommonOperationData)
-> OriginationOperation
-> OriginationOperation
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Mutez -> CommonOperationData -> CommonOperationData
updateCommonDataForFee Mutez
fee)
            Either TransactionOperation OriginationOperation
opToRun
          )
        (\Either TransactionOperation OriginationOperation
op -> do
          ByteString
forgedOp <- NonEmpty (Either TransactionOperation OriginationOperation)
-> m ByteString
forgeOp (NonEmpty (Either TransactionOperation OriginationOperation)
 -> m ByteString)
-> NonEmpty (Either TransactionOperation OriginationOperation)
-> m ByteString
forall a b. (a -> b) -> a -> b
$ OneItem
  (NonEmpty (Either TransactionOperation OriginationOperation))
-> NonEmpty (Either TransactionOperation OriginationOperation)
forall x. One x => OneItem x -> x
one Either TransactionOperation OriginationOperation
OneItem
  (NonEmpty (Either TransactionOperation OriginationOperation))
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 -> TezosInt64 -> Mutez
computeFee FeeConstants
ocFeeConstants Int
fullForgedOpLength TezosInt64
gasLimit) Mutez -> Mutez
forall a. a -> a
id Maybe Mutez
mbFee
            , Maybe (Signature, ByteString)
mExtra
            )
          )

      (Either TransactionOperation OriginationOperation,
 Maybe (Signature, ByteString))
-> m (Either TransactionOperation OriginationOperation,
      Maybe (Signature, ByteString))
forall (m :: * -> *) a. Monad m => a -> m a
return (Either TransactionOperation OriginationOperation
op, Maybe (Signature, ByteString)
mReadySignedOp)

  let
    zipWith4NE
      :: (a -> b -> c -> d -> e) -> NonEmpty a -> NonEmpty b -> NonEmpty c -> NonEmpty d
      -> NonEmpty e
    zipWith4NE :: (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 (Either TransactionOperation OriginationOperation)
updOps, NonEmpty (Maybe (Signature, ByteString))
readySignedOps) <- (NonEmpty
   (Either TransactionOperation OriginationOperation,
    Maybe (Signature, ByteString))
 -> (NonEmpty (Either TransactionOperation OriginationOperation),
     NonEmpty (Maybe (Signature, ByteString))))
-> m (NonEmpty
        (Either TransactionOperation OriginationOperation,
         Maybe (Signature, ByteString)))
-> m (NonEmpty (Either TransactionOperation OriginationOperation),
      NonEmpty (Maybe (Signature, ByteString)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap NonEmpty
  (Either TransactionOperation OriginationOperation,
   Maybe (Signature, ByteString))
-> (NonEmpty (Either TransactionOperation OriginationOperation),
    NonEmpty (Maybe (Signature, ByteString)))
forall (f :: * -> *) a b. Functor f => f (a, b) -> (f a, f b)
NE.unzip (m (NonEmpty
      (Either TransactionOperation OriginationOperation,
       Maybe (Signature, ByteString)))
 -> m (NonEmpty (Either TransactionOperation OriginationOperation),
       NonEmpty (Maybe (Signature, ByteString))))
-> (NonEmpty
      (m (Either TransactionOperation OriginationOperation,
          Maybe (Signature, ByteString)))
    -> m (NonEmpty
            (Either TransactionOperation OriginationOperation,
             Maybe (Signature, ByteString))))
-> NonEmpty
     (m (Either TransactionOperation OriginationOperation,
         Maybe (Signature, ByteString)))
-> m (NonEmpty (Either TransactionOperation OriginationOperation),
      NonEmpty (Maybe (Signature, ByteString)))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty
  (m (Either TransactionOperation OriginationOperation,
      Maybe (Signature, ByteString)))
-> m (NonEmpty
        (Either TransactionOperation OriginationOperation,
         Maybe (Signature, ByteString)))
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
sequenceA (NonEmpty
   (m (Either TransactionOperation OriginationOperation,
       Maybe (Signature, ByteString)))
 -> m (NonEmpty (Either TransactionOperation OriginationOperation),
       NonEmpty (Maybe (Signature, ByteString))))
-> NonEmpty
     (m (Either TransactionOperation OriginationOperation,
         Maybe (Signature, ByteString)))
-> m (NonEmpty (Either TransactionOperation OriginationOperation),
      NonEmpty (Maybe (Signature, ByteString)))
forall a b. (a -> b) -> a -> b
$
    (Either TransactionOperation OriginationOperation
 -> Maybe Mutez
 -> AppliedResult
 -> Bool
 -> m (Either TransactionOperation OriginationOperation,
       Maybe (Signature, ByteString)))
-> NonEmpty (Either TransactionOperation OriginationOperation)
-> NonEmpty (Maybe Mutez)
-> NonEmpty AppliedResult
-> NonEmpty Bool
-> NonEmpty
     (m (Either TransactionOperation OriginationOperation,
         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 Either TransactionOperation OriginationOperation
-> Maybe Mutez
-> AppliedResult
-> Bool
-> m (Either TransactionOperation OriginationOperation,
      Maybe (Signature, ByteString))
updateOp NonEmpty (Either TransactionOperation OriginationOperation)
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 (Either TransactionOperation OriginationOperation)
-> m ByteString
forgeOp NonEmpty (Either TransactionOperation OriginationOperation)
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
-> Text
-> NonEmpty (Either TransactionOperation OriginationOperation)
-> Signature
-> PreApplyOperation
PreApplyOperation
        { paoProtocol :: Text
paoProtocol = BlockConstants -> Text
bcProtocol BlockConstants
ocBlockConstants
        , paoBranch :: Text
paoBranch = Text
ocLastBlockHash
        , paoContents :: NonEmpty (Either TransactionOperation OriginationOperation)
paoContents = NonEmpty (Either TransactionOperation OriginationOperation)
updOps
        , paoSignature :: Signature
paoSignature = Signature
signature'
        }
  NonEmpty AppliedResult
ars2 <- Either RunOperation PreApplyOperation -> m (NonEmpty AppliedResult)
forall (m :: * -> *).
HasTezosRpc m =>
Either RunOperation PreApplyOperation -> m (NonEmpty AppliedResult)
getAppliedResults (PreApplyOperation -> Either RunOperation PreApplyOperation
forall a b. b -> Either a b
Right PreApplyOperation
preApplyOp)
  case SingI runMode => Sing runMode
forall k (a :: k). SingI a => Sing a
sing @runMode of
    Sing runMode
SDryRun -> do
      let fees :: NonEmpty TezosMutez
fees = ((Either TransactionOperation OriginationOperation -> TezosMutez)
 -> NonEmpty (Either TransactionOperation OriginationOperation)
 -> NonEmpty TezosMutez)
-> NonEmpty (Either TransactionOperation OriginationOperation)
-> (Either TransactionOperation OriginationOperation -> TezosMutez)
-> NonEmpty TezosMutez
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Either TransactionOperation OriginationOperation -> TezosMutez)
-> NonEmpty (Either TransactionOperation OriginationOperation)
-> NonEmpty TezosMutez
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map NonEmpty (Either TransactionOperation OriginationOperation)
updOps ((Either TransactionOperation OriginationOperation -> TezosMutez)
 -> NonEmpty TezosMutez)
-> (Either TransactionOperation OriginationOperation -> TezosMutez)
-> NonEmpty TezosMutez
forall a b. (a -> b) -> a -> b
$ \case
            Left (TransactionOperation CommonOperationData
commonData TezosMutez
_ Address
_ ParametersInternal
_) -> CommonOperationData -> TezosMutez
codFee CommonOperationData
commonData
            Right (OriginationOperation CommonOperationData
commonData TezosMutez
_ OriginationScript
_) -> CommonOperationData -> TezosMutez
codFee CommonOperationData
commonData
      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
SRealRun -> do
      OperationHash
operationHash <- HexJSONByteString -> m OperationHash
forall (m :: * -> *).
HasTezosRpc m =>
HexJSONByteString -> m OperationHash
injectOperation (ByteString -> HexJSONByteString
HexJSONByteString ByteString
signedOp)
      OperationHash -> m ()
forall (m :: * -> *). HasTezosClient m => OperationHash -> m ()
waitForOperation OperationHash
operationHash
      let contractAddrs :: NonEmpty [Address]
contractAddrs = AppliedResult -> [Address]
arOriginatedContracts (AppliedResult -> [Address])
-> NonEmpty AppliedResult -> NonEmpty [Address]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty AppliedResult
ars2
      NonEmpty (Either () Address)
opsRes <- NonEmpty (Either TransactionData OriginationData, [Address])
-> ((Either TransactionData OriginationData, [Address])
    -> m (Either () Address))
-> m (NonEmpty (Either () Address))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM (NonEmpty (Either TransactionData OriginationData)
-> NonEmpty [Address]
-> NonEmpty (Either TransactionData OriginationData, [Address])
forall a b. NonEmpty a -> NonEmpty b -> NonEmpty (a, b)
NE.zip NonEmpty (Either TransactionData OriginationData)
operations NonEmpty [Address]
contractAddrs) (((Either TransactionData OriginationData, [Address])
  -> m (Either () Address))
 -> m (NonEmpty (Either () Address)))
-> ((Either TransactionData OriginationData, [Address])
    -> m (Either () Address))
-> m (NonEmpty (Either () Address))
forall a b. (a -> b) -> a -> b
$ \case
        (Left TransactionData
_, []) ->
          Either () Address -> m (Either () Address)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either () Address -> m (Either () Address))
-> Either () Address -> m (Either () Address)
forall a b. (a -> b) -> a -> b
$ () -> Either () Address
forall a b. a -> Either a b
Left ()
        (Left TransactionData
_, [Address]
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
+|
            [Address] -> Builder
forall (f :: * -> *) a. (Foldable f, Buildable a) => f a -> Builder
listF [Address]
addrs Builder -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
""
          return $ () -> Either () Address
forall a b. a -> Either a b
Left ()
        (Right OriginationData
_, []) ->
          IncorrectRpcResponse -> m (Either () Address)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM IncorrectRpcResponse
RpcOriginatedNoContracts
        (Right OriginationData{Bool
Maybe Mutez
Mutez
Value st
Contract cp st
AliasHint
odMbFee :: Maybe Mutez
odStorage :: Value st
odContract :: Contract cp st
odBalance :: Mutez
odName :: AliasHint
odReplaceExisting :: Bool
odMbFee :: OriginationData -> Maybe Mutez
odStorage :: ()
odContract :: ()
odBalance :: OriginationData -> Mutez
odReplaceExisting :: OriginationData -> Bool
odName :: OriginationData -> AliasHint
..}, [Address
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
+| Address
addr Address -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
" for " Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+| AliasHint
odName AliasHint -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ Builder
"\n"
          Bool -> Address -> AliasOrAliasHint -> m ()
forall (m :: * -> *).
HasTezosClient m =>
Bool -> Address -> AliasOrAliasHint -> m ()
rememberContract Bool
odReplaceExisting Address
addr (AliasHint -> AliasOrAliasHint
AnAliasHint AliasHint
odName)
          Alias
alias <- AddressOrAlias -> m Alias
forall (m :: * -> *). HasTezosClient m => AddressOrAlias -> m Alias
getAlias (AddressOrAlias -> m Alias) -> AddressOrAlias -> m Alias
forall a b. (a -> b) -> a -> b
$ Address -> AddressOrAlias
AddressResolved Address
addr
          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
<> Alias -> Text
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty Alias
alias
          return $ Address -> Either () Address
forall a b. b -> Either a b
Right Address
addr
        (Right OriginationData
_, addrs :: [Address]
addrs@(Address
_ : Address
_ : [Address]
_)) ->
          IncorrectRpcResponse -> m (Either () Address)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (IncorrectRpcResponse -> m (Either () Address))
-> IncorrectRpcResponse -> m (Either () Address)
forall a b. (a -> b) -> a -> b
$ [Address] -> IncorrectRpcResponse
RpcOriginatedMoreContracts [Address]
addrs
      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 (Either () Address)
opsRes)
  where
    logStatistics :: AppliedResult -> m ()
    logStatistics :: AppliedResult -> m ()
logStatistics AppliedResult
ar = do
      let showTezosInt64 :: TezosInt64 -> Text
showTezosInt64 = Int64 -> Text
forall b a. (Show a, IsString b) => a -> b
show (Int64 -> Text) -> (TezosInt64 -> Int64) -> TezosInt64 -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TezosInt64 -> 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 gas: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> TezosInt64 -> Text
showTezosInt64 (AppliedResult -> TezosInt64
arConsumedGas 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
<> TezosInt64 -> Text
showTezosInt64 (AppliedResult -> TezosInt64
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
<> TezosInt64 -> Text
showTezosInt64 (AppliedResult -> TezosInt64
arPaidStorageDiff AppliedResult
ar)

    prohibitContractSender :: Address -> Either TransactionData OriginationData -> m ()
    prohibitContractSender :: Address -> Either TransactionData OriginationData -> m ()
prohibitContractSender Address
addr Either TransactionData OriginationData
op = case (Address
addr, Either TransactionData OriginationData
op) of
      (KeyAddress KeyHash
_, Either TransactionData OriginationData
_) -> m ()
forall (f :: * -> *). Applicative f => f ()
pass
      (ContractAddress ContractHash
_, Left TransactionData
_) -> 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
$ Address -> Text -> TezosClientError
ContractSender Address
addr Text
"transfer"
      (ContractAddress ContractHash
_, Right OriginationData
_) -> 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
$ Address -> Text -> TezosClientError
ContractSender Address
addr Text
"origination"