diff --git a/plutus-contract/src/Plutus/Contract/Test.hs b/plutus-contract/src/Plutus/Contract/Test.hs index d0d9b9d417..79a8d467af 100644 --- a/plutus-contract/src/Plutus/Contract/Test.hs +++ b/plutus-contract/src/Plutus/Contract/Test.hs @@ -342,8 +342,7 @@ endpointAvailable contract inst = TracePredicate $ tell @(Doc Void) ("missing endpoint:" <+> fromString (symbolVal (Proxy :: Proxy l))) pure False -tx - :: forall w s e a. +tx :: forall w s e a. ( Monoid w ) => Contract w s e a diff --git a/plutus-contract/src/Plutus/Contract/Wallet.hs b/plutus-contract/src/Plutus/Contract/Wallet.hs index 66186b0202..2440df2114 100644 --- a/plutus-contract/src/Plutus/Contract/Wallet.hs +++ b/plutus-contract/src/Plutus/Contract/Wallet.hs @@ -34,7 +34,7 @@ import Control.Monad.Freer.Error (Error, throwError) import Data.Aeson (FromJSON (parseJSON), Object, ToJSON (toJSON), Value (String), object, withObject, (.:), (.=)) import Data.Aeson.Extras qualified as JSON import Data.Aeson.Types (Parser, parseFail) -import Data.Bifunctor (first) +import Data.Bifunctor (Bifunctor (bimap), first) import Data.Map (Map) import Data.Map qualified as Map import Data.Maybe (mapMaybe) @@ -47,9 +47,7 @@ import Ledger (DCert, Redeemer, StakingCredential, txRedeemers) import Ledger qualified (ScriptPurpose (..)) import Ledger qualified as P import Ledger.Ada qualified as Ada -import Ledger.Constraints (mustPayToAddress) -import Ledger.Constraints.OffChain (UnbalancedTx (unBalancedTxRequiredSignatories, unBalancedTxUtxoIndex), - unBalancedTxTx) +import Ledger.Constraints (UnbalancedTx (UnbalancedCardanoTx, UnbalancedEmulatorTx), mustPayToAddress) import Ledger.Tx (CardanoTx, TxId (TxId), TxIn (..), TxOutRef, getCardanoTxInputs, txInRef) import Ledger.Validation (CardanoLedgerError, fromPlutusIndex, makeTransactionBody) import Ledger.Value (currencyMPSHash) @@ -253,19 +251,20 @@ export :: P.Params -> UnbalancedTx -> Either CardanoLedgerError ExportTx -export params utx = - let requiredSigners = Set.toList (unBalancedTxRequiredSignatories utx) - fromCardanoTx ctx = do - utxo <- fromPlutusIndex $ P.UtxoIndex (unBalancedTxUtxoIndex utx) +export params (UnbalancedEmulatorTx tx sigs utxos) = + let requiredSigners = Set.toList sigs + in ExportTx + <$> bimap Right (C.makeSignedTransaction []) (CardanoAPI.toCardanoTxBody params requiredSigners tx) + <*> first Right (mkInputs (P.pNetworkId params) utxos) + <*> pure (mkRedeemers tx) +export params (UnbalancedCardanoTx tx utxos) = + let fromCardanoTx ctx = do + utxo <- fromPlutusIndex $ P.UtxoIndex utxos makeTransactionBody params utxo ctx in ExportTx - <$> fmap (C.makeSignedTransaction []) - (either - fromCardanoTx - (first Right . CardanoAPI.toCardanoTxBody params requiredSigners) - (unBalancedTxTx utx)) - <*> first Right (mkInputs (P.pNetworkId params) (unBalancedTxUtxoIndex utx)) - <*> either (const $ Right []) (Right . mkRedeemers) (unBalancedTxTx utx) + <$> fmap (C.makeSignedTransaction []) (fromCardanoTx tx) + <*> first Right (mkInputs (P.pNetworkId params) utxos) + <*> pure [] mkInputs :: C.NetworkId -> Map Plutus.TxOutRef P.TxOut -> Either CardanoAPI.ToCardanoError [ExportTxInput] mkInputs networkId = traverse (uncurry (toExportTxInput networkId)) . Map.toList @@ -283,6 +282,7 @@ toExportTxInput networkId Plutus.TxOutRef{Plutus.txOutRefId, Plutus.txOutRefIdx} <*> pure otherQuantities -- TODO: Here there's hidden error of script DCert missing its redeemer - this just counts as no DCert. Don't know if bad. +-- TODO: Refactor with getGardanoTxRedeemers once we are ceady to move to Cardano Txs mkRedeemers :: P.Tx -> [ExportTxRedeemer] mkRedeemers = map (uncurry scriptPurposeToExportRedeemer) . Map.assocs . txRedeemers diff --git a/plutus-contract/src/Wallet/Emulator/Wallet.hs b/plutus-contract/src/Wallet/Emulator/Wallet.hs index c7f6aed379..0442651118 100644 --- a/plutus-contract/src/Wallet/Emulator/Wallet.hs +++ b/plutus-contract/src/Wallet/Emulator/Wallet.hs @@ -318,15 +318,15 @@ handleBalance :: handleBalance utx = do utxo <- get >>= ownOutputs params@Params { pNetworkId } <- WAPI.getClientParams - let requiredSigners = Set.toList (U.unBalancedTxRequiredSignatories utx) - eitherTx = U.unBalancedTxTx utx + let eitherTx = U.unBalancedTxTx utx plUtxo = traverse (Tx.toTxOut pNetworkId) utxo mappedUtxo <- either (throwError . WAPI.ToCardanoError) pure plUtxo cUtxoIndex <- handleError eitherTx $ fromPlutusIndex $ UtxoIndex $ U.unBalancedTxUtxoIndex utx <> mappedUtxo case eitherTx of Right _ -> do -- Find the fixed point of fee calculation, trying maximally n times to prevent an infinite loop - let calcFee n fee = do + let requiredSigners = Set.toList (U.unBalancedTxRequiredSignatories utx) + calcFee n fee = do tx <- handleBalanceTx utxo (utx & U.tx . Ledger.fee .~ fee) newFee <- handleError (Right tx) $ estimateTransactionFee params cUtxoIndex requiredSigners tx if newFee /= fee diff --git a/plutus-contract/test/Spec/Contract/Tx/Constraints/RequiredSigner.hs b/plutus-contract/test/Spec/Contract/Tx/Constraints/RequiredSigner.hs index e3a1e554fb..4d87ca117b 100644 --- a/plutus-contract/test/Spec/Contract/Tx/Constraints/RequiredSigner.hs +++ b/plutus-contract/test/Spec/Contract/Tx/Constraints/RequiredSigner.hs @@ -11,22 +11,26 @@ import Control.Monad (void) import Data.Void (Void) import Test.Tasty (TestTree, testGroup) +import Data.Default (Default (def)) +import Data.Map as M import Data.Maybe (fromJust) -import Data.String (fromString) import Data.Text qualified as Text import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.CardanoWallet as CW +import Ledger.CardanoWallet qualified as CW import Ledger.Constraints.OffChain qualified as Constraints hiding (requiredSignatories) -import Ledger.Constraints.OnChain.V1 qualified as Constraints +import Ledger.Constraints.OnChain.V2 qualified as Constraints import Ledger.Constraints.TxConstraints qualified as Constraints import Ledger.Tx qualified as Tx -import Ledger.Typed.Scripts qualified as Scripts +import Ledger.Tx.Constraints qualified as TxCons import Plutus.Contract as Con -import Plutus.Contract.Test (assertFailedTransaction, assertValidatedTransactionCount, checkPredicateOptions, - defaultCheckOptions, mockWalletPaymentPubKey, mockWalletPaymentPubKeyHash, w1, w2) +import Plutus.Contract.Test (assertFailedTransaction, assertValidatedTransactionCount, changeInitialWalletValue, + checkPredicateOptions, defaultCheckOptions, mockWalletPaymentPubKeyHash, w1, w2) +import Plutus.Script.Utils.V2.Typed.Scripts as PSU.V2 +import Plutus.Script.Utils.V2.Typed.Scripts qualified as Scripts import Plutus.Trace qualified as Trace import Plutus.V1.Ledger.Scripts (ScriptError (EvaluationError), unitDatum) +import Plutus.V2.Ledger.Api qualified as PV2 import PlutusTx qualified import Prelude import Wallet.Emulator.Wallet (signPrivateKeys, walletToMockWallet) @@ -40,10 +44,19 @@ tests = , otherWalletNoSigningProcess , phase2FailureMustBeSignedBy , withoutOffChainMustBeSignedBy + -- When we'll have enough constraints, reuse the previous tests + , cardanoTxOwnWallet + , cardanoTxOtherWalletNoSigningProcess ] -mustBeSignedByContract :: Ledger.PaymentPubKey -> Ledger.PaymentPubKeyHash -> Contract () Empty ContractError () -mustBeSignedByContract pk pkh = do +w1PubKey :: Ledger.PaymentPubKeyHash +w1PubKey = mockWalletPaymentPubKeyHash w1 + +w2PubKey :: Ledger.PaymentPubKeyHash +w2PubKey = mockWalletPaymentPubKeyHash w2 + +mustBeSignedByContract :: Ledger.PaymentPubKeyHash -> Ledger.PaymentPubKeyHash -> Contract () Empty ContractError () +mustBeSignedByContract paymentPubKey signedPubKey = do let lookups1 = Constraints.typedValidatorLookups mustBeSignedByTypedValidator tx1 = Constraints.mustPayToTheScriptWithDatumInTx () @@ -55,17 +68,17 @@ mustBeSignedByContract pk pkh = do let lookups2 = Constraints.typedValidatorLookups mustBeSignedByTypedValidator <> Constraints.unspentOutputs utxos - <> Constraints.paymentPubKey pk + <> Constraints.paymentPubKeyHash paymentPubKey tx2 = - Constraints.collectFromTheScript utxos pkh + Constraints.collectFromTheScript utxos signedPubKey <> Constraints.mustIncludeDatumInTx unitDatum - <> Constraints.mustBeSignedBy pkh + <> Constraints.mustBeSignedBy signedPubKey logInfo @String $ "Required Signatories: " ++ show (Constraints.requiredSignatories tx2) ledgerTx2 <- submitTxConstraintsWith @UnitTest lookups2 tx2 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx2 -withoutOffChainMustBeSignedByContract :: Ledger.PaymentPubKey -> Ledger.PaymentPubKeyHash -> Contract () Empty ContractError () -withoutOffChainMustBeSignedByContract pk pkh = do +withoutOffChainMustBeSignedByContract :: Ledger.PaymentPubKeyHash -> Ledger.PaymentPubKeyHash -> Contract () Empty ContractError () +withoutOffChainMustBeSignedByContract paymentPubKey signedPubKey = do let lookups1 = Constraints.typedValidatorLookups mustBeSignedByTypedValidator tx1 = Constraints.mustPayToTheScriptWithDatumInTx () @@ -77,9 +90,9 @@ withoutOffChainMustBeSignedByContract pk pkh = do let lookups2 = Constraints.typedValidatorLookups mustBeSignedByTypedValidator <> Constraints.unspentOutputs utxos - <> Constraints.paymentPubKey pk + <> Constraints.paymentPubKeyHash paymentPubKey tx2 = - Constraints.collectFromTheScript utxos pkh + Constraints.collectFromTheScript utxos signedPubKey <> Constraints.mustIncludeDatumInTx unitDatum logInfo @String $ "Required Signatories: " ++ show (Constraints.requiredSignatories tx2) ledgerTx2 <- submitTxConstraintsWith @UnitTest lookups2 tx2 @@ -87,52 +100,42 @@ withoutOffChainMustBeSignedByContract pk pkh = do ownWallet :: TestTree ownWallet = - let pk = mockWalletPaymentPubKey w1 - pkh = mockWalletPaymentPubKeyHash w1 - trace = do - void $ Trace.activateContractWallet w1 $ mustBeSignedByContract pk pkh - void $ Trace.waitNSlots 1 + let trace = do + void $ Trace.activateContractWallet w1 $ mustBeSignedByContract w1PubKey w1PubKey + void Trace.nextSlot in checkPredicateOptions defaultCheckOptions "own wallet's signature passes on-chain mustBeSignedBy validation" (assertValidatedTransactionCount 2) (void trace) otherWallet :: TestTree -- must use Trace.setSigningProcess for w2 otherWallet = - let pk = mockWalletPaymentPubKey w2 - pkh = mockWalletPaymentPubKeyHash w2 - trace = do - Trace.setSigningProcess w1 (Just $ signPrivateKeys [paymentPrivateKey $ fromJust $ walletToMockWallet w1, paymentPrivateKey $ fromJust $ walletToMockWallet w2]) - void $ Trace.activateContractWallet w1 $ mustBeSignedByContract pk pkh - void $ Trace.waitNSlots 1 + let trace = do + Trace.setSigningProcess w1 (Just $ signPrivateKeys [CW.paymentPrivateKey $ fromJust $ walletToMockWallet w1, CW.paymentPrivateKey $ fromJust $ walletToMockWallet w2]) + void $ Trace.activateContractWallet w1 $ mustBeSignedByContract w2PubKey w2PubKey + void Trace.nextSlot in checkPredicateOptions defaultCheckOptions "other wallet's signature passes on-chain mustBeSignedBy validation" (assertValidatedTransactionCount 2) (void trace) otherWalletNoSigningProcess :: TestTree otherWalletNoSigningProcess = - let pk = mockWalletPaymentPubKey w2 - pkh = mockWalletPaymentPubKeyHash w2 - trace = do - void $ Trace.activateContractWallet w1 $ mustBeSignedByContract pk pkh - void $ Trace.waitNSlots 1 + let trace = do + void $ Trace.activateContractWallet w1 $ mustBeSignedByContract w2PubKey w2PubKey + void Trace.nextSlot in checkPredicateOptions defaultCheckOptions "without Trace.setSigningProcess fails phase-1 validation" (assertFailedTransaction (\_ err -> case err of {Ledger.CardanoLedgerValidationError msg -> Text.isInfixOf "MissingRequiredSigners" msg; _ -> False })) (void trace) withoutOffChainMustBeSignedBy :: TestTree -- there's no "required signer" in the txbody logs but still passes phase-2 so it must be there. Raised https://github.com/input-output-hk/plutus-apps/issues/645. It'd be good to check log output for expected required signer pubkey in these tests. withoutOffChainMustBeSignedBy = - let pk = mockWalletPaymentPubKey w1 - pkh = mockWalletPaymentPubKeyHash w1 - trace = do - void $ Trace.activateContractWallet w1 $ withoutOffChainMustBeSignedByContract pk pkh - void $ Trace.waitNSlots 1 + let trace = do + void $ Trace.activateContractWallet w1 $ withoutOffChainMustBeSignedByContract w1PubKey w1PubKey + void Trace.nextSlot in checkPredicateOptions defaultCheckOptions "without mustBeSignedBy off-chain constraint required signer is not included in txbody so phase-2 validation fails" (assertFailedTransaction (\_ err -> case err of {Ledger.ScriptFailure (EvaluationError ("L4":_) _) -> True; _ -> False })) (void trace) phase2FailureMustBeSignedBy :: TestTree phase2FailureMustBeSignedBy = - let pk = mockWalletPaymentPubKey w1 - pkh = Ledger.PaymentPubKeyHash $ fromString "76aaef06f38cc98ed08ceb168ddb55bab2ea5df43a6847a99f086fc9" :: Ledger.PaymentPubKeyHash - trace = do - void $ Trace.activateContractWallet w1 $ withoutOffChainMustBeSignedByContract pk pkh - void $ Trace.waitNSlots 1 + let trace = do + void $ Trace.activateContractWallet w1 $ withoutOffChainMustBeSignedByContract w1PubKey w2PubKey + void Trace.nextSlot in checkPredicateOptions defaultCheckOptions "with wrong pubkey fails on-chain mustBeSignedBy constraint validation" (assertFailedTransaction (\_ err -> case err of {Ledger.ScriptFailure (EvaluationError ("L4":_) _) -> True; _ -> False })) (void trace) @@ -147,7 +150,7 @@ instance Scripts.ValidatorTypes UnitTest where type instance RedeemerType UnitTest = Ledger.PaymentPubKeyHash {-# INLINEABLE mustBeSignedByValidator #-} -mustBeSignedByValidator :: () -> Ledger.PaymentPubKeyHash -> Ledger.ScriptContext -> Bool +mustBeSignedByValidator :: () -> Ledger.PaymentPubKeyHash -> PV2.ScriptContext -> Bool mustBeSignedByValidator _ pkh = Constraints.checkScriptContext @Void @Void (Constraints.mustBeSignedBy pkh) mustBeSignedByTypedValidator :: Scripts.TypedValidator UnitTest @@ -156,3 +159,70 @@ mustBeSignedByTypedValidator = Scripts.mkTypedValidator @UnitTest $$(PlutusTx.compile [|| wrap ||]) where wrap = Scripts.mkUntypedValidator + + +-- plutus-tx-constraints tests +-- all below to be covered by the above tests when the corresponding constraints will be implemented +-- for CardanoTx + + +cardanoTxOwnWalletContract + :: Ledger.PaymentPubKeyHash + -> Ledger.PaymentPubKeyHash + -> Contract () EmptySchema ContractError () +cardanoTxOwnWalletContract paymentPubKey signedPubKey = do + let mkTx lookups constraints = either (error . show) id $ TxCons.mkTx @UnitTest def lookups constraints + + utxos <- ownUtxos + let get3 (a:b:c:_) = (a, b, c) + get3 _ = error "Spec.Contract.TxConstraints.get3: not enough inputs" + ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ M.toList utxos + lookups1 = Constraints.typedValidatorLookups mustBeSignedByTypedValidator + <> Constraints.unspentOutputs utxos + tx1 = Constraints.mustPayToTheScriptWithDatumInTx + () + (Ada.lovelaceValueOf 25_000_000) + <> Constraints.mustSpendPubKeyOutput utxoRefForBalance1 + <> Constraints.mustUseOutputAsCollateral utxoRefForBalance1 + ledgerTx1 <- submitTxConstraintsWith lookups1 tx1 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 + + -- Trying to unlock the Ada in the script address + scriptUtxos <- utxosAt (Ledger.scriptHashAddress $ Scripts.validatorHash mustBeSignedByTypedValidator) + utxos' <- ownUtxos + let lookups2 = + Constraints.typedValidatorLookups mustBeSignedByTypedValidator + <> Constraints.unspentOutputs (M.singleton utxoRef utxo <> scriptUtxos <> utxos') + <> Constraints.paymentPubKeyHash paymentPubKey + tx2 = + Constraints.collectFromTheScript utxos signedPubKey + <> Constraints.mustIncludeDatumInTx unitDatum + <> Constraints.mustUseOutputAsCollateral utxoRefForBalance2 + <> Constraints.mustSpendPubKeyOutput utxoRefForBalance2 + <> Constraints.mustBeSignedBy signedPubKey + logInfo @String $ "Required Signatories: " ++ show (Constraints.requiredSignatories tx2) + submitTxConfirmed $ mkTx lookups2 tx2 + +cardanoTxOwnWallet :: TestTree +cardanoTxOwnWallet = + let trace = do + void $ Trace.activateContractWallet w1 $ cardanoTxOwnWalletContract w1PubKey w1PubKey + void Trace.nextSlot + in checkPredicateOptions + (changeInitialWalletValue w1 (const $ Ada.adaValueOf 1000) defaultCheckOptions) + "own wallet's signature passes on-chain mustBeSignedBy validation with cardano tx" + (assertValidatedTransactionCount 2) + (void trace) + +cardanoTxOtherWalletNoSigningProcess :: TestTree +cardanoTxOtherWalletNoSigningProcess = + let trace = do + void $ Trace.activateContractWallet w1 $ cardanoTxOwnWalletContract w2PubKey w2PubKey + void Trace.nextSlot + in checkPredicateOptions + -- Needed to manually balance the transaction + -- We may remove it once PLT-321 + (changeInitialWalletValue w1 (const $ Ada.adaValueOf 1000) defaultCheckOptions) + "without Trace.setSigningProcess fails phase-1 validation" + (assertFailedTransaction (\_ err -> case err of {Ledger.CardanoLedgerValidationError msg -> Text.isInfixOf "MissingRequiredSigners" msg; _ -> False })) + (void trace) diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs index ea06855c78..e4d9cd4589 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs @@ -35,6 +35,7 @@ module Ledger.Constraints.OffChain( , ownPaymentPubKeyHash , ownStakingCredential , paymentPubKey + , paymentPubKeyHash -- * Constraints resolution , SomeLookupsAndConstraints(..) , UnbalancedTx(..) @@ -249,7 +250,12 @@ otherData dt = -- | A script lookups value with a payment public key paymentPubKey :: PaymentPubKey -> ScriptLookups a paymentPubKey (PaymentPubKey pk) = - mempty { slPaymentPubKeyHashes = Set.singleton (PaymentPubKeyHash $ pubKeyHash pk) } + paymentPubKeyHash (PaymentPubKeyHash $ pubKeyHash pk) + +-- | A script lookups value with a payment public key +paymentPubKeyHash :: PaymentPubKeyHash -> ScriptLookups a +paymentPubKeyHash pkh = + mempty { slPaymentPubKeyHashes = Set.singleton pkh } -- | A script lookups value with a payment public key hash. -- @@ -291,13 +297,8 @@ data UnbalancedTx -- Simply refers to 'slTxOutputs' of 'ScriptLookups'. } | UnbalancedCardanoTx - { unBalancedCardanoBuildTx :: C.CardanoBuildTx - , unBalancedTxRequiredSignatories :: Set PaymentPubKeyHash - -- ^ These are all the payment public keys that should be used to request the - -- signatories from the user's wallet. The signatories are what is required to - -- sign the transaction before submitting it to the blockchain. Transaction - -- validation will fail if the transaction is not signed by the required wallet. - , unBalancedTxUtxoIndex :: Map TxOutRef TxOut + { unBalancedCardanoBuildTx :: C.CardanoBuildTx + , unBalancedTxUtxoIndex :: Map TxOutRef TxOut -- ^ Utxo lookups that are used for adding inputs to the 'UnbalancedTx'. -- Simply refers to 'slTxOutputs' of 'ScriptLookups'. } @@ -325,10 +326,9 @@ instance Pretty UnbalancedTx where , hang 2 $ vsep $ "Requires signatures:" : (pretty <$> Set.toList rs) , hang 2 $ vsep $ "Utxo index:" : (pretty <$> Map.toList utxo) ] - pretty (UnbalancedCardanoTx utx rs utxo) = + pretty (UnbalancedCardanoTx utx utxo) = vsep [ hang 2 $ vsep ["Tx (cardano-api Representation):", pretty utx] - , hang 2 $ vsep $ "Requires signatures:" : (pretty <$> Set.toList rs) , hang 2 $ vsep $ "Utxo index:" : (pretty <$> Map.toList utxo) ] diff --git a/plutus-ledger/src/Ledger/Tx.hs b/plutus-ledger/src/Ledger/Tx.hs index 44dea4c24b..16429f7168 100644 --- a/plutus-ledger/src/Ledger/Tx.hs +++ b/plutus-ledger/src/Ledger/Tx.hs @@ -53,6 +53,7 @@ module Ledger.Tx , getCardanoTxCollateralInputs , getCardanoTxOutRefs , getCardanoTxOutputs + , getCardanoTxRedeemers , getCardanoTxSpentOutputs , getCardanoTxProducedOutputs , getCardanoTxReturnCollateral diff --git a/plutus-ledger/src/Ledger/Validation.hs b/plutus-ledger/src/Ledger/Validation.hs index a3d7f2fa8c..d92805823d 100644 --- a/plutus-ledger/src/Ledger/Validation.hs +++ b/plutus-ledger/src/Ledger/Validation.hs @@ -304,7 +304,7 @@ makeTransactionBody -> Either CardanoLedgerError (C.Api.TxBody C.Api.BabbageEra) makeTransactionBody params utxo txBodyContent = do txTmp <- first Right $ makeSignedTransaction [] <$> P.makeTransactionBody (Just $ emulatorPParams params) mempty txBodyContent - exUnits <- bimap Left id $ (Map.map snd) <$> getTxExUnitsWithLogs params utxo txTmp + exUnits <- first Left $ Map.map snd <$> getTxExUnitsWithLogs params utxo txTmp first Right $ P.makeTransactionBody (Just $ emulatorPParams params) exUnits txBodyContent diff --git a/plutus-tx-constraints/src/Ledger/Tx/Constraints.hs b/plutus-tx-constraints/src/Ledger/Tx/Constraints.hs index ca90c37b36..86485936c2 100644 --- a/plutus-tx-constraints/src/Ledger/Tx/Constraints.hs +++ b/plutus-tx-constraints/src/Ledger/Tx/Constraints.hs @@ -79,6 +79,7 @@ module Ledger.Tx.Constraints( , OC.plutusV2OtherScript , OC.otherData , OC.paymentPubKey + , OC.paymentPubKeyHash , OC.ownPaymentPubKeyHash , OC.ownStakingCredential -- * Deprecated diff --git a/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs b/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs index 4566bdfa9f..dbbda586b9 100644 --- a/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs +++ b/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs @@ -34,6 +34,7 @@ module Ledger.Tx.Constraints.OffChain( , P.ownPaymentPubKeyHash , P.ownStakingCredential , P.paymentPubKey + , P.paymentPubKeyHash -- * Constraints resolution , P.SomeLookupsAndConstraints(..) , UnbalancedTx(..) @@ -41,7 +42,6 @@ module Ledger.Tx.Constraints.OffChain( , tx , txValidityRange , txOuts - , P.requiredSignatories , P.utxoIndex , emptyUnbalancedTx , P.adjustUnbalancedTx @@ -61,6 +61,7 @@ import Data.Aeson (FromJSON, ToJSON) import Data.Bifunctor (first) import Data.Either (partitionEithers) import Data.Foldable (traverse_) +import Data.Set qualified as Set import GHC.Generics (Generic) import Ledger (POSIXTimeRange, Params (..), networkIdL, pProtocolParams) import Ledger.Constraints qualified as P @@ -85,6 +86,7 @@ makeLensesFor [ ("txIns", "txIns'") , ("txInsCollateral", "txInsCollateral'") , ("txInsReference", "txInsReference'") + , ("txExtraKeyWits", "txExtraKeyWits'") , ("txOuts", "txOuts'") , ("txValidityRange", "txValidityRange'") ] ''C.TxBodyContent @@ -100,6 +102,14 @@ txInsCollateral = coerced . txInsCollateral' . iso toList fromList fromList [] = C.TxInsCollateralNone fromList txins = C.TxInsCollateral C.CollateralInBabbageEra txins +txExtraKeyWits :: Lens' C.CardanoBuildTx (Set.Set (C.Hash C.PaymentKey)) +txExtraKeyWits = coerced . txExtraKeyWits' . iso toSet fromSet + where + toSet C.TxExtraKeyWitnessesNone = mempty + toSet (C.TxExtraKeyWitnesses _ txwits) = Set.fromList txwits + fromSet s | null s = C.TxExtraKeyWitnessesNone + | otherwise = C.TxExtraKeyWitnesses C.ExtraKeyWitnessesInBabbageEra $ Set.toList s + txInsReference :: Lens' C.CardanoBuildTx [C.TxIn] txInsReference = coerced . txInsReference' . iso toList fromList where @@ -139,7 +149,7 @@ emptyCardanoBuildTx p = C.CardanoBuildTx $ C.TxBodyContent } emptyUnbalancedTx :: Params -> UnbalancedTx -emptyUnbalancedTx params = UnbalancedCardanoTx (emptyCardanoBuildTx params) mempty mempty +emptyUnbalancedTx params = UnbalancedCardanoTx (emptyCardanoBuildTx params) mempty initialState :: Params -> P.ConstraintProcessingState initialState params = P.ConstraintProcessingState @@ -278,7 +288,9 @@ processConstraint = \case $ guard $ is Tx._PublicKeyDecoratedTxOut txout txIn <- throwLeft ToCardanoError $ C.toCardanoTxIn txo unbalancedTx . tx . txIns <>= [(txIn, C.BuildTxWith (C.KeyWitness C.KeyWitnessForSpending))] - + P.MustBeSignedBy pk -> do + ekw <- either (throwError . ToCardanoError) pure $ C.toCardanoPaymentKeyHash pk + unbalancedTx . tx . txExtraKeyWits <>= Set.singleton ekw P.MustSpendScriptOutput txo redeemer mref -> do txout <- lookupTxOutRef txo mkWitness <- case mref of