-- SPDX-FileCopyrightText: 2021 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA
-- | Functions to submit transactions via @octez-client@ and node RPC.

module Morley.Client.Action.Transaction
  ( runTransactions
  , lRunTransactions

  -- * Transfer
  , transfer
  , lTransfer
  , transferTicket

  -- Datatypes for batch transactions
  , TD (..)
  , LTransactionData (..)
  , TransactionData (..)
  , TransferTicketData (..)
  ) where

import Lorentz.Constraints
import Morley.Client.Action.Common
import Morley.Client.Action.Operation
import Morley.Client.Logging
import Morley.Client.RPC.Class
import Morley.Client.RPC.Types
import Morley.Client.TezosClient.Class
import Morley.Client.Types
import Morley.Michelson.Typed qualified as T
import Morley.Michelson.Typed.Scope
import Morley.Michelson.Untyped.Entrypoints
import Morley.Tezos.Address
import Morley.Tezos.Core (Mutez)

-- | Perform sequence of transactions to the contract. Returns operation hash
-- and a list of RPC responses, or 'Nothing' in case an empty list was provided.
runTransactions
  :: forall m env.
     ( HasTezosRpc m
     , HasTezosClient m
     , WithClientLog env m
     )
  => ImplicitAddressWithAlias -> [TransactionData]
  -> m (Maybe (OperationHash, [OperationInfo Result]))
runTransactions :: forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddressWithAlias
-> [TransactionData]
-> m (Maybe (OperationHash, [OperationInfo Result]))
runTransactions ImplicitAddressWithAlias
sender [TransactionData]
transactions = MaybeT m (OperationHash, [OperationInfo Result])
-> m (Maybe (OperationHash, [OperationInfo Result]))
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT do
  NonEmpty TransactionData
ts <- Maybe (NonEmpty TransactionData)
-> MaybeT m (NonEmpty TransactionData)
forall (m :: * -> *) a. Applicative m => Maybe a -> MaybeT m a
hoistMaybe (Maybe (NonEmpty TransactionData)
 -> MaybeT m (NonEmpty TransactionData))
-> Maybe (NonEmpty TransactionData)
-> MaybeT m (NonEmpty TransactionData)
forall a b. (a -> b) -> a -> b
$ [TransactionData] -> Maybe (NonEmpty TransactionData)
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty [TransactionData]
transactions
  m (OperationHash, [OperationInfo Result])
-> MaybeT m (OperationHash, [OperationInfo Result])
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (OperationHash, [OperationInfo Result])
 -> MaybeT m (OperationHash, [OperationInfo Result]))
-> m (OperationHash, [OperationInfo Result])
-> MaybeT m (OperationHash, [OperationInfo Result])
forall a b. (a -> b) -> a -> b
$ (NonEmpty (OperationInfo Result) -> [OperationInfo Result])
-> (OperationHash, NonEmpty (OperationInfo Result))
-> (OperationHash, [OperationInfo Result])
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second NonEmpty (OperationInfo Result) -> [OperationInfo Result]
forall t. Container t => t -> [Element t]
toList ((OperationHash, NonEmpty (OperationInfo Result))
 -> (OperationHash, [OperationInfo Result]))
-> m (OperationHash, NonEmpty (OperationInfo Result))
-> m (OperationHash, [OperationInfo Result])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ImplicitAddressWithAlias
-> NonEmpty TransactionData
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddressWithAlias
-> NonEmpty TransactionData
-> m (OperationHash, NonEmpty (OperationInfo Result))
runTransactionsNonEmpty ImplicitAddressWithAlias
sender NonEmpty TransactionData
ts

-- | Perform sequence of transactions to the contract. Returns operation hash
-- and a list of RPC responses.
runTransactionsNonEmpty
  :: forall m env.
     ( HasTezosRpc m
     , HasTezosClient m
     , WithClientLog env m
     )
  => ImplicitAddressWithAlias -> NonEmpty TransactionData
  -> m (OperationHash, NonEmpty (OperationInfo Result))
runTransactionsNonEmpty :: forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddressWithAlias
-> NonEmpty TransactionData
-> m (OperationHash, NonEmpty (OperationInfo Result))
runTransactionsNonEmpty ImplicitAddressWithAlias
sender =
  ImplicitAddressWithAlias
-> NonEmpty (OperationInfo ClientInput)
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddressWithAlias
-> NonEmpty (OperationInfo ClientInput)
-> m (OperationHash, NonEmpty (OperationInfo Result))
runOperationsNonEmpty ImplicitAddressWithAlias
sender (NonEmpty (OperationInfo ClientInput)
 -> m (OperationHash, NonEmpty (OperationInfo Result)))
-> (NonEmpty TransactionData
    -> NonEmpty (OperationInfo ClientInput))
-> NonEmpty TransactionData
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TransactionData -> OperationInfo ClientInput)
-> NonEmpty TransactionData -> NonEmpty (OperationInfo ClientInput)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map TransactionData -> OperationInfo ClientInput
forall i. TransferInfo i -> OperationInfo i
OpTransfer

-- | Lorentz version of 'TransactionData'.
data LTransactionData where
  LTransactionData ::
    forall (t :: Type). NiceParameter t =>
    TD t -> LTransactionData

-- | Lorentz version of 'runTransactions'
lRunTransactions
  :: forall m env.
    ( HasTezosRpc m
    , HasTezosClient m
    , WithClientLog env m
    )
  => ImplicitAddressWithAlias
  -> [LTransactionData]
  -> m (Maybe (OperationHash, [OperationInfo Result]))
lRunTransactions :: forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddressWithAlias
-> [LTransactionData]
-> m (Maybe (OperationHash, [OperationInfo Result]))
lRunTransactions ImplicitAddressWithAlias
sender [LTransactionData]
transactions =
  ImplicitAddressWithAlias
-> [TransactionData]
-> m (Maybe (OperationHash, [OperationInfo Result]))
forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddressWithAlias
-> [TransactionData]
-> m (Maybe (OperationHash, [OperationInfo Result]))
runTransactions ImplicitAddressWithAlias
sender ([TransactionData]
 -> m (Maybe (OperationHash, [OperationInfo Result])))
-> [TransactionData]
-> m (Maybe (OperationHash, [OperationInfo Result]))
forall a b. (a -> b) -> a -> b
$ (LTransactionData -> TransactionData)
-> [LTransactionData] -> [TransactionData]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map LTransactionData -> TransactionData
convertLTransactionData [LTransactionData]
transactions
  where
    convertLTransactionData :: LTransactionData -> TransactionData
    convertLTransactionData :: LTransactionData -> TransactionData
convertLTransactionData (LTransactionData TD{tdParam :: forall t. TD t -> t
tdParam=t -> Value (ToT t)
forall a. IsoValue a => a -> Value (ToT a)
T.toVal -> Value (ToT t)
tdParam, Maybe Mutez
EpName
Mutez
L1Address
tdMbFee :: forall t. TD t -> Maybe Mutez
tdEpName :: forall t. TD t -> EpName
tdAmount :: forall t. TD t -> Mutez
tdReceiver :: forall t. TD t -> L1Address
tdMbFee :: Maybe Mutez
tdEpName :: EpName
tdAmount :: Mutez
tdReceiver :: L1Address
..}) =
      TD (Value (ToT t)) -> TransactionData
forall (t :: T).
ParameterScope t =>
TD (Value t) -> TransactionData
TransactionData TD :: forall t. L1Address -> Mutez -> EpName -> t -> Maybe Mutez -> TD t
TD{Maybe Mutez
EpName
Mutez
L1Address
Value (ToT t)
tdMbFee :: Maybe Mutez
tdEpName :: EpName
tdAmount :: Mutez
tdReceiver :: L1Address
tdMbFee :: Maybe Mutez
tdEpName :: EpName
tdAmount :: Mutez
tdReceiver :: L1Address
tdParam :: Value (ToT t)
tdParam :: Value (ToT t)
..}

transfer
  :: forall m t env kind.
    ( HasTezosRpc m
    , HasTezosClient m
    , WithClientLog env m
    , ParameterScope t
    , L1AddressKind kind
    )
  => ImplicitAddressWithAlias
  -> KindedAddress kind
  -> Mutez
  -> EpName
  -> T.Value t
  -> Maybe Mutez
  -> m (OperationHash, [IntOpEvent])
transfer :: forall (m :: * -> *) (t :: T) env (kind :: AddressKind).
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 ParameterScope t, L1AddressKind kind) =>
ImplicitAddressWithAlias
-> KindedAddress kind
-> Mutez
-> EpName
-> Value t
-> Maybe Mutez
-> m (OperationHash, [IntOpEvent])
transfer ImplicitAddressWithAlias
from (KindedAddress kind -> L1Address
forall {k} (c :: k -> Constraint) (f :: k -> *) (a :: k).
c a =>
f a -> Constrained c f
Constrained -> L1Address
tdReceiver) Mutez
tdAmount EpName
tdEpName Value t
tdParam Maybe Mutez
tdMbFee =
  (((OperationHash, NonEmpty (OperationInfo Result))
 -> (OperationHash, [IntOpEvent]))
-> m (OperationHash, NonEmpty (OperationInfo Result))
-> m (OperationHash, [IntOpEvent])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((OperationHash, NonEmpty (OperationInfo Result))
  -> (OperationHash, [IntOpEvent]))
 -> m (OperationHash, NonEmpty (OperationInfo Result))
 -> m (OperationHash, [IntOpEvent]))
-> ((NonEmpty (OperationInfo Result) -> [IntOpEvent])
    -> (OperationHash, NonEmpty (OperationInfo Result))
    -> (OperationHash, [IntOpEvent]))
-> (NonEmpty (OperationInfo Result) -> [IntOpEvent])
-> m (OperationHash, NonEmpty (OperationInfo Result))
-> m (OperationHash, [IntOpEvent])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NonEmpty (OperationInfo Result) -> [IntOpEvent])
-> (OperationHash, NonEmpty (OperationInfo Result))
-> (OperationHash, [IntOpEvent])
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second) ([OperationInfo Result] -> [IntOpEvent]
getEvents ([OperationInfo Result] -> [IntOpEvent])
-> (NonEmpty (OperationInfo Result) -> [OperationInfo Result])
-> NonEmpty (OperationInfo Result)
-> [IntOpEvent]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (OperationInfo Result) -> [OperationInfo Result]
forall t. Container t => t -> [Element t]
toList) (m (OperationHash, NonEmpty (OperationInfo Result))
 -> m (OperationHash, [IntOpEvent]))
-> (TransactionData
    -> m (OperationHash, NonEmpty (OperationInfo Result)))
-> TransactionData
-> m (OperationHash, [IntOpEvent])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ImplicitAddressWithAlias
-> NonEmpty TransactionData
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddressWithAlias
-> NonEmpty TransactionData
-> m (OperationHash, NonEmpty (OperationInfo Result))
runTransactionsNonEmpty ImplicitAddressWithAlias
from (NonEmpty TransactionData
 -> m (OperationHash, NonEmpty (OperationInfo Result)))
-> (TransactionData -> NonEmpty TransactionData)
-> TransactionData
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TransactionData -> NonEmpty TransactionData
forall x. One x => OneItem x -> x
one (TransactionData -> m (OperationHash, [IntOpEvent]))
-> TransactionData -> m (OperationHash, [IntOpEvent])
forall a b. (a -> b) -> a -> b
$ TD (Value t) -> TransactionData
forall (t :: T).
ParameterScope t =>
TD (Value t) -> TransactionData
TransactionData TD :: forall t. L1Address -> Mutez -> EpName -> t -> Maybe Mutez -> TD t
TD{Maybe Mutez
EpName
Mutez
L1Address
Value t
tdMbFee :: Maybe Mutez
tdParam :: Value t
tdEpName :: EpName
tdAmount :: Mutez
tdReceiver :: L1Address
tdMbFee :: Maybe Mutez
tdEpName :: EpName
tdAmount :: Mutez
tdReceiver :: L1Address
tdParam :: Value t
..}
  where
    getEvents :: [OperationInfo Result] -> [IntOpEvent]
getEvents = (OperationInfo Result -> [IntOpEvent])
-> [OperationInfo Result] -> [IntOpEvent]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap \case
      OpTransfer TransferInfo Result
i -> [IntOpEvent]
TransferInfo Result
i
      OperationInfo Result
_ -> []

transferTicket
  :: forall m t env kind.
    ( HasTezosRpc m
    , HasTezosClient m
    , WithClientLog env m
    , ParameterScope t
    , Comparable t
    )
  => ImplicitAddressWithAlias -- ^ Sender
  -> KindedAddress kind -- ^ Destination
  -> ContractAddress -- ^ Ticketer
  -> T.Value t -- ^ Ticket value
  -> Natural -- ^ Ticket amount
  -> EpName -- ^ Destination entrypoint
  -> Maybe Mutez -- ^ Fee
  -> m (OperationHash, [IntOpEvent])
transferTicket :: forall (m :: * -> *) (t :: T) env (kind :: AddressKind).
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 ParameterScope t, Comparable t) =>
ImplicitAddressWithAlias
-> KindedAddress kind
-> ContractAddress
-> Value t
-> Natural
-> EpName
-> Maybe Mutez
-> m (OperationHash, [IntOpEvent])
transferTicket ImplicitAddressWithAlias
from (KindedAddress kind -> Constrained NullConstraint KindedAddress
forall {k} (c :: k -> Constraint) (f :: k -> *) (a :: k).
c a =>
f a -> Constrained c f
Constrained -> Constrained NullConstraint KindedAddress
ttdDestination)
  (ContractAddress -> Constrained NullConstraint KindedAddress
forall {k} (c :: k -> Constraint) (f :: k -> *) (a :: k).
c a =>
f a -> Constrained c f
Constrained -> Constrained NullConstraint KindedAddress
ttdTicketTicketer) Value t
ttdTicketContents
  Natural
ttdTicketAmount EpName
ttdEntrypoint Maybe Mutez
ttdMbFee =
  (((OperationHash, NonEmpty (OperationInfo Result))
 -> (OperationHash, [IntOpEvent]))
-> m (OperationHash, NonEmpty (OperationInfo Result))
-> m (OperationHash, [IntOpEvent])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((OperationHash, NonEmpty (OperationInfo Result))
  -> (OperationHash, [IntOpEvent]))
 -> m (OperationHash, NonEmpty (OperationInfo Result))
 -> m (OperationHash, [IntOpEvent]))
-> ((NonEmpty (OperationInfo Result) -> [IntOpEvent])
    -> (OperationHash, NonEmpty (OperationInfo Result))
    -> (OperationHash, [IntOpEvent]))
-> (NonEmpty (OperationInfo Result) -> [IntOpEvent])
-> m (OperationHash, NonEmpty (OperationInfo Result))
-> m (OperationHash, [IntOpEvent])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NonEmpty (OperationInfo Result) -> [IntOpEvent])
-> (OperationHash, NonEmpty (OperationInfo Result))
-> (OperationHash, [IntOpEvent])
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second) ([OperationInfo Result] -> [IntOpEvent]
getEvents ([OperationInfo Result] -> [IntOpEvent])
-> (NonEmpty (OperationInfo Result) -> [OperationInfo Result])
-> NonEmpty (OperationInfo Result)
-> [IntOpEvent]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (OperationInfo Result) -> [OperationInfo Result]
forall t. Container t => t -> [Element t]
toList) (m (OperationHash, NonEmpty (OperationInfo Result))
 -> m (OperationHash, [IntOpEvent]))
-> (TransferTicketData
    -> m (OperationHash, NonEmpty (OperationInfo Result)))
-> TransferTicketData
-> m (OperationHash, [IntOpEvent])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ImplicitAddressWithAlias
-> NonEmpty (OperationInfo ClientInput)
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall (m :: * -> *) env.
(HasTezosRpc m, HasTezosClient m, WithClientLog env m) =>
ImplicitAddressWithAlias
-> NonEmpty (OperationInfo ClientInput)
-> m (OperationHash, NonEmpty (OperationInfo Result))
runOperationsNonEmpty ImplicitAddressWithAlias
from (NonEmpty (OperationInfo ClientInput)
 -> m (OperationHash, NonEmpty (OperationInfo Result)))
-> (TransferTicketData -> NonEmpty (OperationInfo ClientInput))
-> TransferTicketData
-> m (OperationHash, NonEmpty (OperationInfo Result))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OperationInfo ClientInput -> NonEmpty (OperationInfo ClientInput)
forall x. One x => OneItem x -> x
one (OperationInfo ClientInput -> NonEmpty (OperationInfo ClientInput))
-> (TransferTicketData -> OperationInfo ClientInput)
-> TransferTicketData
-> NonEmpty (OperationInfo ClientInput)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TransferTicketData -> OperationInfo ClientInput
forall i. TransferTicketInfo i -> OperationInfo i
OpTransferTicket (TransferTicketData -> m (OperationHash, [IntOpEvent]))
-> TransferTicketData -> m (OperationHash, [IntOpEvent])
forall a b. (a -> b) -> a -> b
$
    TransferTicketData :: forall (t :: T).
(ParameterScope t, Comparable t) =>
Value t
-> Constrained NullConstraint KindedAddress
-> Natural
-> Constrained NullConstraint KindedAddress
-> EpName
-> Maybe Mutez
-> TransferTicketData
TransferTicketData{Natural
Maybe Mutez
EpName
Constrained NullConstraint KindedAddress
Value t
ttdMbFee :: Maybe Mutez
ttdEntrypoint :: EpName
ttdDestination :: Constrained NullConstraint KindedAddress
ttdTicketAmount :: Natural
ttdTicketTicketer :: Constrained NullConstraint KindedAddress
ttdTicketContents :: Value t
ttdMbFee :: Maybe Mutez
ttdEntrypoint :: EpName
ttdTicketAmount :: Natural
ttdTicketContents :: Value t
ttdTicketTicketer :: Constrained NullConstraint KindedAddress
ttdDestination :: Constrained NullConstraint KindedAddress
..}
  where
    getEvents :: [OperationInfo Result] -> [IntOpEvent]
getEvents = (OperationInfo Result -> [IntOpEvent])
-> [OperationInfo Result] -> [IntOpEvent]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap \case
      OpTransferTicket TransferTicketInfo Result
i -> [IntOpEvent]
TransferTicketInfo Result
i
      OperationInfo Result
_ -> []

lTransfer
  :: forall m t env kind.
    ( HasTezosRpc m
    , HasTezosClient m
    , WithClientLog env m
    , NiceParameter t
    , L1AddressKind kind
    )
  => ImplicitAddressWithAlias
  -> KindedAddress kind
  -> Mutez
  -> EpName
  -> t
  -> Maybe Mutez
  -> m (OperationHash, [IntOpEvent])
lTransfer :: forall (m :: * -> *) t env (kind :: AddressKind).
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 NiceParameter t, L1AddressKind kind) =>
ImplicitAddressWithAlias
-> KindedAddress kind
-> Mutez
-> EpName
-> t
-> Maybe Mutez
-> m (OperationHash, [IntOpEvent])
lTransfer ImplicitAddressWithAlias
from KindedAddress kind
to Mutez
amount EpName
epName = ImplicitAddressWithAlias
-> KindedAddress kind
-> Mutez
-> EpName
-> Value (ToT t)
-> Maybe Mutez
-> m (OperationHash, [IntOpEvent])
forall (m :: * -> *) (t :: T) env (kind :: AddressKind).
(HasTezosRpc m, HasTezosClient m, WithClientLog env m,
 ParameterScope t, L1AddressKind kind) =>
ImplicitAddressWithAlias
-> KindedAddress kind
-> Mutez
-> EpName
-> Value t
-> Maybe Mutez
-> m (OperationHash, [IntOpEvent])
transfer ImplicitAddressWithAlias
from KindedAddress kind
to Mutez
amount EpName
epName (Value (ToT t) -> Maybe Mutez -> m (OperationHash, [IntOpEvent]))
-> (t -> Value (ToT t))
-> t
-> Maybe Mutez
-> m (OperationHash, [IntOpEvent])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t -> Value (ToT t)
forall a. IsoValue a => a -> Value (ToT a)
T.toVal