module Cooked.MockChain.GenerateTx.Input (toTxInAndWitness) where

import Cardano.Api qualified as Cardano
import Cooked.MockChain.BlockChain
import Cooked.MockChain.GenerateTx.Common
import Cooked.MockChain.GenerateTx.Witness
import Cooked.Skeleton
import Ledger.Tx.CardanoAPI qualified as Ledger
import Plutus.Script.Utils.Scripts qualified as Script
import PlutusLedgerApi.V3 qualified as Api

-- | Converts a 'TxSkel' input, which consists of a 'Api.TxOutRef' and a
-- 'TxSkelIn', into a 'Cardano.TxIn', together with the appropriate witness.
toTxInAndWitness ::
  (MonadBlockChainBalancing m) =>
  (Api.TxOutRef, TxSkelRedeemer) ->
  m (Cardano.TxIn, Cardano.BuildTxWith Cardano.BuildTx (Cardano.Witness Cardano.WitCtxTxIn Cardano.ConwayEra))
toTxInAndWitness :: forall (m :: * -> *).
MonadBlockChainBalancing m =>
(TxOutRef, TxSkelRedeemer)
-> m (TxIn, BuildTxWith BuildTx (Witness WitCtxTxIn ConwayEra))
toTxInAndWitness (TxOutRef
txOutRef, TxSkelRedeemer
txSkelRedeemer) = do
  Api.TxOut (Api.Address Credential
cred Maybe StakingCredential
_) Value
_ OutputDatum
datum Maybe ScriptHash
_ <- String -> Maybe TxOut -> m TxOut
forall (m :: * -> *) a.
MonadError MockChainError m =>
String -> Maybe a -> m a
throwOnMaybe String
"toCollateralTriplet: unresolved txOutRefs" (Maybe TxOut -> m TxOut) -> m (Maybe TxOut) -> m TxOut
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< TxOutRef -> m (Maybe TxOut)
forall (m :: * -> *).
MonadBlockChainBalancing m =>
TxOutRef -> m (Maybe TxOut)
txOutByRef TxOutRef
txOutRef
  Witness WitCtxTxIn ConwayEra
witness <- case Credential
cred of
    Api.PubKeyCredential PubKeyHash
_ -> Witness WitCtxTxIn ConwayEra -> m (Witness WitCtxTxIn ConwayEra)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Witness WitCtxTxIn ConwayEra -> m (Witness WitCtxTxIn ConwayEra))
-> Witness WitCtxTxIn ConwayEra -> m (Witness WitCtxTxIn ConwayEra)
forall a b. (a -> b) -> a -> b
$ KeyWitnessInCtx WitCtxTxIn -> Witness WitCtxTxIn ConwayEra
forall witctx era. KeyWitnessInCtx witctx -> Witness witctx era
Cardano.KeyWitness KeyWitnessInCtx WitCtxTxIn
Cardano.KeyWitnessForSpending
    Api.ScriptCredential (Api.ScriptHash BuiltinByteString
scriptHash) -> do
      Versioned Validator
validator <- String -> Maybe (Versioned Validator) -> m (Versioned Validator)
forall (m :: * -> *) a.
MonadError MockChainError m =>
String -> Maybe a -> m a
throwOnMaybe String
"toTxInAndWitness: Unknown validator" (Maybe (Versioned Validator) -> m (Versioned Validator))
-> m (Maybe (Versioned Validator)) -> m (Versioned Validator)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ValidatorHash -> m (Maybe (Versioned Validator))
forall (m :: * -> *).
MonadBlockChainBalancing m =>
ValidatorHash -> m (Maybe (Versioned Validator))
validatorFromHash (BuiltinByteString -> ValidatorHash
Script.ValidatorHash BuiltinByteString
scriptHash)
      ScriptDatum WitCtxTxIn
scriptDatum <- case OutputDatum
datum of
        OutputDatum
Api.NoOutputDatum -> String -> m (ScriptDatum WitCtxTxIn)
forall (m :: * -> *) a.
MonadError MockChainError m =>
String -> m a
throwOnString String
"toTxInAndWitness: No datum found on script output"
        Api.OutputDatum Datum
_ -> ScriptDatum WitCtxTxIn -> m (ScriptDatum WitCtxTxIn)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptDatum WitCtxTxIn
Cardano.InlineScriptDatum
        Api.OutputDatumHash DatumHash
datumHash -> do
          Datum
sDatum <- String -> Maybe Datum -> m Datum
forall (m :: * -> *) a.
MonadError MockChainError m =>
String -> Maybe a -> m a
throwOnMaybe String
"toTxInAndWitness: Unknown validator" (Maybe Datum -> m Datum) -> m (Maybe Datum) -> m Datum
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< DatumHash -> m (Maybe Datum)
forall (m :: * -> *).
MonadBlockChainBalancing m =>
DatumHash -> m (Maybe Datum)
datumFromHash DatumHash
datumHash
          ScriptDatum WitCtxTxIn -> m (ScriptDatum WitCtxTxIn)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptDatum WitCtxTxIn -> m (ScriptDatum WitCtxTxIn))
-> ScriptDatum WitCtxTxIn -> m (ScriptDatum WitCtxTxIn)
forall a b. (a -> b) -> a -> b
$ HashableScriptData -> ScriptDatum WitCtxTxIn
Cardano.ScriptDatumForTxIn (HashableScriptData -> ScriptDatum WitCtxTxIn)
-> HashableScriptData -> ScriptDatum WitCtxTxIn
forall a b. (a -> b) -> a -> b
$ BuiltinData -> HashableScriptData
Ledger.toCardanoScriptData (BuiltinData -> HashableScriptData)
-> BuiltinData -> HashableScriptData
forall a b. (a -> b) -> a -> b
$ Datum -> BuiltinData
Api.getDatum Datum
sDatum
      ScriptWitnessInCtx WitCtxTxIn
-> ScriptWitness WitCtxTxIn ConwayEra
-> Witness WitCtxTxIn ConwayEra
forall witctx era.
ScriptWitnessInCtx witctx
-> ScriptWitness witctx era -> Witness witctx era
Cardano.ScriptWitness ScriptWitnessInCtx WitCtxTxIn
Cardano.ScriptWitnessForSpending (ScriptWitness WitCtxTxIn ConwayEra
 -> Witness WitCtxTxIn ConwayEra)
-> m (ScriptWitness WitCtxTxIn ConwayEra)
-> m (Witness WitCtxTxIn ConwayEra)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Versioned Validator
-> TxSkelRedeemer
-> ScriptDatum WitCtxTxIn
-> m (ScriptWitness WitCtxTxIn ConwayEra)
forall (m :: * -> *) a b.
(MonadBlockChainBalancing m, ToVersionedScript a) =>
a
-> TxSkelRedeemer -> ScriptDatum b -> m (ScriptWitness b ConwayEra)
toScriptWitness Versioned Validator
validator TxSkelRedeemer
txSkelRedeemer ScriptDatum WitCtxTxIn
scriptDatum
  String
-> (TxIn
    -> (TxIn, BuildTxWith BuildTx (Witness WitCtxTxIn ConwayEra)))
-> Either ToCardanoError TxIn
-> m (TxIn, BuildTxWith BuildTx (Witness WitCtxTxIn ConwayEra))
forall (m :: * -> *) a b.
MonadError MockChainError m =>
String -> (a -> b) -> Either ToCardanoError a -> m b
throwOnToCardanoErrorOrApply
    String
"toTxInAndWitness: Unable to translate TxOutRef"
    (,Witness WitCtxTxIn ConwayEra
-> BuildTxWith BuildTx (Witness WitCtxTxIn ConwayEra)
forall a. a -> BuildTxWith BuildTx a
Cardano.BuildTxWith Witness WitCtxTxIn ConwayEra
witness)
    (TxOutRef -> Either ToCardanoError TxIn
Ledger.toCardanoTxIn TxOutRef
txOutRef)