diff --git a/nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-contract.nix b/nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-contract.nix index 0efcae45aa..9d285dc8f9 100644 --- a/nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-contract.nix +++ b/nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-contract.nix @@ -91,6 +91,7 @@ "Data/UUID/Extras" "Plutus/Contract" "Plutus/Contract/Effects" + "Plutus/Contract/Error" "Plutus/Contract/Request" "Plutus/Contract/Checkpoint" "Plutus/Contract/Constraints" diff --git a/nix/pkgs/haskell/materialized-linux/.plan.nix/plutus-contract.nix b/nix/pkgs/haskell/materialized-linux/.plan.nix/plutus-contract.nix index 0efcae45aa..9d285dc8f9 100644 --- a/nix/pkgs/haskell/materialized-linux/.plan.nix/plutus-contract.nix +++ b/nix/pkgs/haskell/materialized-linux/.plan.nix/plutus-contract.nix @@ -91,6 +91,7 @@ "Data/UUID/Extras" "Plutus/Contract" "Plutus/Contract/Effects" + "Plutus/Contract/Error" "Plutus/Contract/Request" "Plutus/Contract/Checkpoint" "Plutus/Contract/Constraints" diff --git a/nix/pkgs/haskell/materialized-windows/.plan.nix/plutus-contract.nix b/nix/pkgs/haskell/materialized-windows/.plan.nix/plutus-contract.nix index 0efcae45aa..9d285dc8f9 100644 --- a/nix/pkgs/haskell/materialized-windows/.plan.nix/plutus-contract.nix +++ b/nix/pkgs/haskell/materialized-windows/.plan.nix/plutus-contract.nix @@ -91,6 +91,7 @@ "Data/UUID/Extras" "Plutus/Contract" "Plutus/Contract/Effects" + "Plutus/Contract/Error" "Plutus/Contract/Request" "Plutus/Contract/Checkpoint" "Plutus/Contract/Constraints" diff --git a/playground-common/src/PSGenerator/Common.hs b/playground-common/src/PSGenerator/Common.hs index c775c35061..bd81d38b1a 100644 --- a/playground-common/src/PSGenerator/Common.hs +++ b/playground-common/src/PSGenerator/Common.hs @@ -43,6 +43,7 @@ import Plutus.ChainIndex.UtxoState (InsertUtxoFailed, InsertUtxoPosition, Rollba import Plutus.Contract.Checkpoint (CheckpointError) import Plutus.Contract.Effects (ActiveEndpoint, BalanceTxResponse, ChainIndexQuery, ChainIndexResponse, PABReq, PABResp, WriteBalancedTxResponse) +import Plutus.Contract.Error (AssertionError, ContractError, MatchingError) import Plutus.Contract.Resumable (IterationID, Request, RequestID, Response) import Plutus.Trace.Emulator.Types (ContractInstanceLog, ContractInstanceMsg, ContractInstanceTag, EmulatorRuntimeError, UserThreadMsg) @@ -52,9 +53,8 @@ import Schema (FormArgumentF, FormSchema) import Wallet.API (WalletAPIError) import Wallet.Emulator.Types qualified as EM import Wallet.Rollup.Types (AnnotatedTx, BeneficialOwner, DereferencedInput, SequenceId, TxKey) -import Wallet.Types (AssertionError, ContractActivityStatus, ContractError, ContractInstanceId, EndpointDescription, - EndpointValue, MatchingError, Notification, NotificationError) - +import Wallet.Types (ContractActivityStatus, ContractInstanceId, EndpointDescription, EndpointValue, Notification, + NotificationError) psJson :: PSType psJson = TypeInfo "web-common" "Data.RawJson" "RawJson" [] diff --git a/plutus-contract/plutus-contract.cabal b/plutus-contract/plutus-contract.cabal index 0fc4601029..fa0aef6252 100644 --- a/plutus-contract/plutus-contract.cabal +++ b/plutus-contract/plutus-contract.cabal @@ -43,6 +43,7 @@ library Data.UUID.Extras Plutus.Contract Plutus.Contract.Effects + Plutus.Contract.Error Plutus.Contract.Request Plutus.Contract.Checkpoint Plutus.Contract.Constraints diff --git a/plutus-contract/src/Plutus/Contract.hs b/plutus-contract/src/Plutus/Contract.hs index b3db8992cd..bfe9811105 100644 --- a/plutus-contract/src/Plutus/Contract.hs +++ b/plutus-contract/src/Plutus/Contract.hs @@ -4,24 +4,24 @@ {-# LANGUAGE MonoLocalBinds #-} module Plutus.Contract( Contract(..) - , ContractError(..) - , AsContractError(..) - , IsContract(..) + , Plutus.Contract.Types.ContractError(..) + , Plutus.Contract.Types.AsContractError(..) + , Plutus.Contract.Types.IsContract(..) , (>>) - , throwError - , handleError - , mapError - , runError + , Plutus.Contract.Types.throwError + , Plutus.Contract.Types.handleError + , Plutus.Contract.Types.mapError + , Plutus.Contract.Types.runError -- * Select , Promise - , awaitPromise - , promiseMap - , promiseBind + , Plutus.Contract.Types.awaitPromise + , Plutus.Contract.Types.promiseMap + , Plutus.Contract.Types.promiseBind , both - , selectEither - , select - , selectList - , never + , Plutus.Contract.Types.selectEither + , Plutus.Contract.Types.select + , Plutus.Contract.Types.selectList + , Plutus.Contract.Types.never -- * Dealing with time , Request.awaitSlot , Request.isSlot @@ -90,10 +90,10 @@ module Plutus.Contract( -- ** Tx output confirmation , Request.awaitTxOutStatusChange -- * Checkpoints - , checkpoint - , checkpointLoop - , AsCheckpointError(..) - , CheckpointError(..) + , Plutus.Contract.Types.checkpoint + , Plutus.Contract.Types.checkpointLoop + , Plutus.Contract.Types.AsCheckpointError(..) + , Plutus.Contract.Types.CheckpointError(..) -- * Logging , module Logging -- * Row-related things @@ -110,10 +110,8 @@ import Plutus.Contract.Request (ContractRow) import Plutus.Contract.Request qualified as Request import Plutus.Contract.Schema qualified as Schema import Plutus.Contract.Typed.Tx as Tx (collectFromScript, collectFromScriptFilter) -import Plutus.Contract.Types (AsCheckpointError (..), AsContractError (..), CheckpointError (..), Contract (..), - ContractError (..), IsContract (..), Promise (..), checkpoint, checkpointLoop, - handleError, mapError, never, promiseBind, promiseMap, runError, select, selectEither, - selectList, throwError) +import Plutus.Contract.Types (Contract (Contract), Promise, select) +import Plutus.Contract.Types qualified import Control.Monad.Freer.Writer qualified as W import Data.Functor.Apply (liftF2) diff --git a/plutus-contract/src/Plutus/Contract/Error.hs b/plutus-contract/src/Plutus/Contract/Error.hs new file mode 100644 index 0000000000..b504fdfdc9 --- /dev/null +++ b/plutus-contract/src/Plutus/Contract/Error.hs @@ -0,0 +1,111 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} + +module Plutus.Contract.Error + ( ContractError(..) + , AsContractError(..) + , MatchingError(..) + , AsMatchingError(..) + , AssertionError(..) + , AsAssertionError(..) + ) where + +import Control.Lens (prism') +import Control.Lens.TH (makeClassyPrisms) +import Data.Aeson (FromJSON, ToJSON) +import Data.Aeson qualified as Aeson +import Data.String (IsString (fromString)) +import Data.Text (Text) +import Data.Text qualified as T +import GHC.Generics (Generic) +import Prettyprinter (Pretty (pretty), viaShow, (<+>)) + +import Data.Aeson qualified as JSON +import Ledger.Constraints.OffChain (MkTxError) +import Plutus.Contract.Checkpoint (AsCheckpointError (_CheckpointError), CheckpointError) +import Plutus.Contract.Effects (ChainIndexResponse) +import Wallet.Error (WalletAPIError) +import Wallet.Types (EndpointDescription (EndpointDescription), EndpointValue (EndpointValue)) + +-- | An error +newtype MatchingError = WrongVariantError { unWrongVariantError :: Text } + deriving stock (Eq, Ord, Show, Generic) + deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) +makeClassyPrisms ''MatchingError + +instance Pretty MatchingError where + pretty = \case + WrongVariantError t -> "Wrong variant:" <+> pretty t + +-- | An error emitted when an 'Assertion' fails. +newtype AssertionError = GenericAssertion { unAssertionError :: T.Text } + deriving stock (Show, Eq, Generic) + deriving anyclass (ToJSON, FromJSON) +makeClassyPrisms ''AssertionError + +instance Pretty AssertionError where + pretty = \case + GenericAssertion t -> "Generic assertion:" <+> pretty t + +-- | This lets people use 'T.Text' as their error type. +instance AsAssertionError T.Text where + _AssertionError = prism' (T.pack . show) (const Nothing) + +data ContractError = + WalletContractError WalletAPIError + | ChainIndexContractError T.Text ChainIndexResponse + | EmulatorAssertionContractError AssertionError -- TODO: Why do we need this constructor + | ConstraintResolutionContractError MkTxError + | ResumableContractError MatchingError + | CCheckpointContractError CheckpointError + | EndpointDecodeContractError + { eeEndpointDescription :: EndpointDescription + -- ^ The endpoint description which the decoding error occurred from + , eeEndpointValue :: EndpointValue JSON.Value + -- ^ The endpoint value that was used as an endpoint parameter + , eeErrorMessage :: T.Text + -- ^ JSON decoding error message + } + | OtherContractError T.Text + deriving stock (Show, Eq, Generic) + deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) +makeClassyPrisms ''ContractError + +instance Pretty ContractError where + pretty = \case + WalletContractError e -> "Wallet error:" <+> pretty e + ChainIndexContractError expectedResp actualResp + -> "Wrong response type from chain index request: Expected" + <+> pretty expectedResp + <> ", got" + <+> pretty actualResp + EmulatorAssertionContractError a -> "Emulator assertion error:" <+> pretty a + ConstraintResolutionContractError e -> "Constraint resolution error:" <+> pretty e + ResumableContractError e -> "Resumable error:" <+> pretty e + CCheckpointContractError e -> "Checkpoint error:" <+> pretty e + EndpointDecodeContractError (EndpointDescription ed) (EndpointValue ev) err + -> "Failed to decode endpoint \"" + <> pretty ed + <> "\" with value" + <+> viaShow ev + <> ":" + <+> pretty err + OtherContractError t -> "Other error:" <+> pretty t + +-- | This lets people use 'T.Text' as their error type. +instance AsContractError T.Text where + _ContractError = prism' (T.pack . show) (const Nothing) + +instance IsString ContractError where + fromString = OtherContractError . fromString + +instance AsAssertionError ContractError where + _AssertionError = _EmulatorAssertionContractError + +instance AsCheckpointError ContractError where + _CheckpointError = _CCheckpointContractError diff --git a/plutus-contract/src/Plutus/Contract/Request.hs b/plutus-contract/src/Plutus/Contract/Request.hs index a5ae30527a..08d8f43e94 100644 --- a/plutus-contract/src/Plutus/Contract/Request.hs +++ b/plutus-contract/src/Plutus/Contract/Request.hs @@ -138,9 +138,9 @@ import Wallet.Types (ContractInstanceId, EndpointDescription (EndpointDescriptio import Plutus.ChainIndex (ChainIndexTx, Page (nextPageQuery, pageItems), PageQuery, txOutRefs) import Plutus.ChainIndex.Api (IsUtxoResponse, TxosResponse (paget), UtxosResponse (page)) import Plutus.ChainIndex.Types (RollbackState (Unknown), Tip, TxOutStatus, TxStatus) +import Plutus.Contract.Error (AsContractError (_ChainIndexContractError, _ConstraintResolutionContractError, _EndpointDecodeContractError, _ResumableContractError, _WalletContractError)) import Plutus.Contract.Resumable (prompt) -import Plutus.Contract.Types (AsContractError (_ConstraintResolutionError, _OtherError, _ResumableError, _WalletError), - Contract (Contract), MatchingError (WrongVariantError), Promise (Promise), mapError, +import Plutus.Contract.Types (Contract (Contract), MatchingError (WrongVariantError), Promise (Promise), mapError, runError, throwError) -- | Constraints on the contract schema, ensuring that the labels of the schema @@ -163,7 +163,11 @@ pabReq req prism = Contract $ do x <- prompt @PABResp @PABReq req case preview prism x of Just r -> pure r - _ -> E.throwError @e $ review _ResumableError $ WrongVariantError $ "unexpected answer: " <> tshow x + _ -> + E.throwError @e + $ review _ResumableContractError + $ WrongVariantError + $ "unexpected answer: " <> tshow x -- | Wait until the slot awaitSlot :: @@ -262,8 +266,7 @@ datumFromHash h = do cir <- pabReq (ChainIndexQueryReq $ E.DatumFromHash h) E._ChainIndexQueryResp case cir of E.DatumHashResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request DatumFromHash from the chain index" + r -> throwError $ review _ChainIndexContractError ("DatumHashResponse", r) validatorFromHash :: forall w s e. @@ -275,8 +278,7 @@ validatorFromHash h = do cir <- pabReq (ChainIndexQueryReq $ E.ValidatorFromHash h) E._ChainIndexQueryResp case cir of E.ValidatorHashResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request ValidatorFromHash from the chain index" + r -> throwError $ review _ChainIndexContractError ("ValidatorHashResponse", r) mintingPolicyFromHash :: forall w s e. @@ -288,8 +290,7 @@ mintingPolicyFromHash h = do cir <- pabReq (ChainIndexQueryReq $ E.MintingPolicyFromHash h) E._ChainIndexQueryResp case cir of E.MintingPolicyHashResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request MintingPolicyFromHash from the chain index" + r -> throwError $ review _ChainIndexContractError ("MintingPolicyHashResponse", r) stakeValidatorFromHash :: forall w s e. @@ -301,8 +302,7 @@ stakeValidatorFromHash h = do cir <- pabReq (ChainIndexQueryReq $ E.StakeValidatorFromHash h) E._ChainIndexQueryResp case cir of E.StakeValidatorHashResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request StakeValidatorFromHash from the chain index" + r -> throwError $ review _ChainIndexContractError ("StakeValidatorHashResponse", r) redeemerFromHash :: forall w s e. @@ -314,8 +314,7 @@ redeemerFromHash h = do cir <- pabReq (ChainIndexQueryReq $ E.RedeemerFromHash h) E._ChainIndexQueryResp case cir of E.RedeemerHashResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request RedeemerFromHash from the chain index" + r -> throwError $ review _ChainIndexContractError ("RedeemerHashResponse", r) txOutFromRef :: forall w s e. @@ -327,8 +326,7 @@ txOutFromRef ref = do cir <- pabReq (ChainIndexQueryReq $ E.TxOutFromRef ref) E._ChainIndexQueryResp case cir of E.TxOutRefResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request TxOutFromRef from the chain index" + r -> throwError $ review _ChainIndexContractError ("TxOutRefResponse", r) txFromTxId :: forall w s e. @@ -340,8 +338,7 @@ txFromTxId txid = do cir <- pabReq (ChainIndexQueryReq $ E.TxFromTxId txid) E._ChainIndexQueryResp case cir of E.TxIdResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request TxFromTxId from the chain index" + r -> throwError $ review _ChainIndexContractError ("TxIdResponse", r) utxoRefMembership :: forall w s e. @@ -353,8 +350,7 @@ utxoRefMembership ref = do cir <- pabReq (ChainIndexQueryReq $ E.UtxoSetMembership ref) E._ChainIndexQueryResp case cir of E.UtxoSetMembershipResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request UtxoSetMembership from the chain index" + r -> throwError $ review _ChainIndexContractError ("UtxoSetMembershipResponse", r) -- | Get the unspent transaction output references at an address. utxoRefsAt :: @@ -368,8 +364,7 @@ utxoRefsAt pq addr = do cir <- pabReq (ChainIndexQueryReq $ E.UtxoSetAtAddress pq $ addressCredential addr) E._ChainIndexQueryResp case cir of E.UtxoSetAtResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request UtxoSetAtAddress from the chain index" + r -> throwError $ review _ChainIndexContractError ("UtxoSetAtResponse", r) -- | Get the unspent transaction output references with a specific currrency ('AssetClass'). utxoRefsWithCurrency :: @@ -383,8 +378,7 @@ utxoRefsWithCurrency pq assetClass = do cir <- pabReq (ChainIndexQueryReq $ E.UtxoSetWithCurrency pq assetClass) E._ChainIndexQueryResp case cir of E.UtxoSetWithCurrencyResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request UtxoSetWithCurrency from the chain index" + r -> throwError $ review _ChainIndexContractError ("UtxoSetWithCurrencyResponse", r) -- | Fold through each 'Page's of unspent 'TxOutRef's at a given 'Address', and -- accumulate the result. @@ -517,8 +511,7 @@ txoRefsAt pq addr = do cir <- pabReq (ChainIndexQueryReq $ E.TxoSetAtAddress pq $ addressCredential addr) E._ChainIndexQueryResp case cir of E.TxoSetAtResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request TxoSetAtAddress from the chain index" + r -> throwError $ review _ChainIndexContractError ("TxoSetAtAddress", r) -- | Get the transactions for a list of transaction ids. txsFromTxIds :: @@ -531,8 +524,7 @@ txsFromTxIds txid = do cir <- pabReq (ChainIndexQueryReq $ E.TxsFromTxIds txid) E._ChainIndexQueryResp case cir of E.TxIdsResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request TxsFromTxIds from the chain index" + r -> throwError $ review _ChainIndexContractError ("TxIdsResponse", r) getTip :: forall w s e. @@ -543,8 +535,7 @@ getTip = do cir <- pabReq (ChainIndexQueryReq E.GetTip) E._ChainIndexQueryResp case cir of E.GetTipResponse r -> pure r - _ -> throwError $ review _OtherError - $ Text.pack "Could not request GetTip from the chain index" + r -> throwError $ review _ChainIndexContractError ("GetTipResponse", r) -- | Wait until the target slot and get the unspent transaction outputs at an -- address. @@ -712,14 +703,23 @@ endpoint ) => (a -> Contract w s e b) -> Promise w s e b endpoint f = Promise $ do - (_, endpointValue) <- pabReq (ExposeEndpointReq $ endpointReq @l @a @s) E._ExposeEndpointResp - a <- decode endpointValue + (ed, ev) <- pabReq (ExposeEndpointReq $ endpointReq @l @a @s) E._ExposeEndpointResp + a <- decode ed ev f a -decode :: forall a w s e. (FromJSON a, AsContractError e) => EndpointValue JSON.Value -> Contract w s e a -decode EndpointValue{unEndpointValue} = - either (throwError . review _OtherError . Text.pack) pure - $ JSON.parseEither JSON.parseJSON unEndpointValue +decode + :: forall a w s e. + ( FromJSON a + , AsContractError e + ) + => EndpointDescription + -> EndpointValue JSON.Value + -> Contract w s e a +decode ed ev@EndpointValue{unEndpointValue} = + either + (\e -> throwError $ review _EndpointDecodeContractError (ed, ev, Text.pack e)) + pure + $ JSON.parseEither JSON.parseJSON unEndpointValue handleEndpoint :: forall l a w s e1 e2 b. @@ -730,8 +730,8 @@ handleEndpoint => (Either e1 a -> Contract w s e2 b) -> Promise w s e2 b handleEndpoint f = Promise $ do a <- runError $ do - (_, endpointValue) <- pabReq (ExposeEndpointReq $ endpointReq @l @a @s) E._ExposeEndpointResp - decode endpointValue + (ed, ev) <- pabReq (ExposeEndpointReq $ endpointReq @l @a @s) E._ExposeEndpointResp + decode ed ev f a -- | Expose an endpoint with some metadata. Return the data that was entered. @@ -746,8 +746,8 @@ endpointWithMeta -> (a -> Contract w s e b) -> Promise w s e b endpointWithMeta meta f = Promise $ do - (_, endpointValue) <- pabReq (ExposeEndpointReq s) E._ExposeEndpointResp - a <- decode endpointValue + (ed, ev) <- pabReq (ExposeEndpointReq s) E._ExposeEndpointResp + a <- decode ed ev f a where s = ActiveEndpoint @@ -784,7 +784,7 @@ balanceTx :: forall w s e. (AsContractError e) => UnbalancedTx -> Contract w s e -- See Note [Injecting errors into the user's error type] balanceTx t = let req = pabReq (BalanceTxReq t) E._BalanceTxResp in - req >>= either (throwError . review _WalletError) pure . view E.balanceTxResponse + req >>= either (throwError . review _WalletContractError) pure . view E.balanceTxResponse -- | Send an balanced transaction to be signed. Returns the ID -- of the final transaction when the transaction was submitted. Throws an @@ -793,7 +793,7 @@ submitBalancedTx :: forall w s e. (AsContractError e) => CardanoTx -> Contract w -- See Note [Injecting errors into the user's error type] submitBalancedTx t = let req = pabReq (WriteBalancedTxReq t) E._WriteBalancedTxResp in - req >>= either (throwError . review _WalletError) pure . view E.writeBalancedTxResponse + req >>= either (throwError . review _WalletContractError) pure . view E.writeBalancedTxResponse -- | Build a transaction that satisfies the constraints, then submit it to the -- network. The constraints do not refer to any typed script inputs or @@ -879,7 +879,7 @@ mkTxConstraints :: forall a w s e. -> TxConstraints (RedeemerType a) (DatumType a) -> Contract w s e UnbalancedTx mkTxConstraints sl constraints = - mapError (review _ConstraintResolutionError) (mkTxContract sl constraints) + mapError (review _ConstraintResolutionContractError) (mkTxContract sl constraints) -- | Build a transaction that satisfies the constraints, then submit it to the -- network. Using the given constraints. diff --git a/plutus-contract/src/Plutus/Contract/StateMachine.hs b/plutus-contract/src/Plutus/Contract/StateMachine.hs index cea724fe85..3a08a27268 100644 --- a/plutus-contract/src/Plutus/Contract/StateMachine.hs +++ b/plutus-contract/src/Plutus/Contract/StateMachine.hs @@ -80,9 +80,9 @@ import Ledger.Typed.Tx (TypedScriptTxOut (TypedScriptTxOut, tyTxOutData, tyTxOut import Ledger.Typed.Tx qualified as Typed import Ledger.Value qualified as Value import Plutus.ChainIndex (ChainIndexTx (_citxInputs)) -import Plutus.Contract (AsContractError (_ConstraintResolutionError, _ContractError), Contract, ContractError, Promise, - awaitPromise, isSlot, isTime, logWarn, mapError, never, ownPaymentPubKeyHash, promiseBind, - select, submitTxConfirmed, utxoIsProduced, utxoIsSpent, utxosAt, utxosTxOutTxAt, +import Plutus.Contract (AsContractError (_ConstraintResolutionContractError, _ContractError), Contract, ContractError, + Promise, awaitPromise, isSlot, isTime, logWarn, mapError, never, ownPaymentPubKeyHash, + promiseBind, select, submitTxConfirmed, utxoIsProduced, utxoIsSpent, utxosAt, utxosTxOutTxAt, utxosTxOutTxFromTx) import Plutus.Contract.Request (mkTxContract) import Plutus.Contract.StateMachine.MintingPolarity (MintingPolarity (Burn, Mint)) @@ -435,7 +435,7 @@ runInitialiseWith customLookups customConstraints StateMachineClient{scInstance} <> foldMap (mintingPolicy . curPolicy . ttOutRef) (smThreadToken stateMachine) <> Constraints.unspentOutputs utxo <> customLookups - utx <- mapError (review _ConstraintResolutionError) (mkTxContract lookups constraints) + utx <- mapError (review _ConstraintResolutionContractError) (mkTxContract lookups constraints) let adjustedUtx = Constraints.adjustUnbalancedTx utx unless (utx == adjustedUtx) $ logWarn @Text $ "Plutus.Contract.StateMachine.runInitialise: " @@ -483,7 +483,7 @@ runGuardedStepWith userLookups userConstraints smc input guard = mapError (revie Right StateMachineTransition{smtConstraints,smtOldState=State{stateData=os}, smtNewState=State{stateData=ns}, smtLookups} -> do pk <- ownPaymentPubKeyHash let lookups = smtLookups { Constraints.slOwnPaymentPubKeyHash = Just pk } - utx <- either (throwing _ConstraintResolutionError) + utx <- either (throwing _ConstraintResolutionContractError) pure (Constraints.mkTx (lookups <> userLookups) (smtConstraints <> userConstraints)) let adjustedUtx = Constraints.adjustUnbalancedTx utx diff --git a/plutus-contract/src/Plutus/Contract/Types.hs b/plutus-contract/src/Plutus/Contract/Types.hs index d9ad0ac0db..ffa1163a2a 100644 --- a/plutus-contract/src/Plutus/Contract/Types.hs +++ b/plutus-contract/src/Plutus/Contract/Types.hs @@ -30,9 +30,9 @@ module Plutus.Contract.Types( , selectList , never -- * Error handling - , ContractError(..) - , AsContractError(..) - , MatchingError(..) + , Plutus.Contract.Error.ContractError(..) + , Plutus.Contract.Error.AsContractError(..) + , Plutus.Contract.Error.MatchingError(..) , mapError , throwError , runError @@ -66,22 +66,21 @@ module Plutus.Contract.Types( , lastLogs ) where -import Control.Applicative -import Control.Lens -import Control.Monad -import Control.Monad.Except (MonadError (..)) -import Control.Monad.Freer +import Control.Lens (Bifunctor (bimap), Iso', iso, makeLenses, over, set, to, unto, view, (&), (.~), (^.)) +import Control.Monad.Except (MonadError (catchError, throwError)) +import Control.Monad.Freer (Eff, Member, interpret, reinterpret, run, send, subsume, type (~>)) import Control.Monad.Freer.Error (Error) import Control.Monad.Freer.Error qualified as E import Control.Monad.Freer.Extras.Log (LogMessage, LogMsg, handleLogIgnore, handleLogWriter) import Control.Monad.Freer.Extras.Modify (raiseEnd, raiseUnder, writeIntoState) -import Control.Monad.Freer.State +import Control.Monad.Freer.State (State, get, put, runState) import Control.Monad.Freer.Writer (Writer) import Control.Monad.Freer.Writer qualified as W import Data.Aeson (Value) import Data.Aeson qualified as Aeson +import Data.Either (fromRight) import Data.Foldable (foldl') -import Data.Functor.Apply (Apply (..)) +import Data.Functor.Apply (Apply, liftF2) import Data.IntervalSet qualified as IS import Data.Map qualified as Map import Data.Maybe (fromMaybe) @@ -89,17 +88,20 @@ import Data.Row (Row) import Data.Sequence (Seq) import GHC.Generics (Generic) -import Plutus.Contract.Checkpoint (AsCheckpointError (..), Checkpoint (..), CheckpointError (..), CheckpointKey, - CheckpointLogMsg, CheckpointStore, completedIntervals, handleCheckpoint, - jsonCheckpoint, jsonCheckpointLoop) -import Plutus.Contract.Resumable hiding (never, responses, select) -import Plutus.Contract.Resumable qualified as Resumable - +import Plutus.Contract.Checkpoint (AsCheckpointError (_CheckpointError), + Checkpoint (AllocateKey, DoCheckpoint, Retrieve, Store), + CheckpointError (JSONDecodeError), CheckpointKey, CheckpointLogMsg, CheckpointStore, + completedIntervals, handleCheckpoint, jsonCheckpoint, jsonCheckpointLoop) import Plutus.Contract.Effects (PABReq, PABResp) +import Plutus.Contract.Error qualified +import Plutus.Contract.Resumable (IterationID, MultiRequestContStatus (AContinuation, AResult), + MultiRequestContinuation (MultiRequestContinuation, ndcCont, ndcRequests), RequestID, + Requests, Response, Responses, Resumable, _Responses, handleResumable, insertResponse, + suspendNonDet) +import Plutus.Contract.Resumable qualified as Resumable import PlutusTx.Applicative qualified as PlutusTx import PlutusTx.Functor qualified as PlutusTx import Prelude as Haskell -import Wallet.Types (AsContractError (..), ContractError (..), MatchingError (..)) -- | Effects that are available to contracts. type ContractEffs w e = @@ -380,7 +382,7 @@ mkResult oldW oldLogs (initialRes, cpKey, cpStore, AccumState newW, newLogs) = { _responses = mempty , _requests = let getRequests = \case { AContinuation MultiRequestContinuation{ndcRequests} -> Just ndcRequests; _ -> Nothing } - in either mempty ((fromMaybe mempty) . (>>= getRequests)) initialRes + in either mempty (fromMaybe mempty . (>>= getRequests)) initialRes , _finalState = let getResult = \case { AResult a -> Just a; _ -> Nothing } in fmap (>>= getResult) initialRes @@ -390,7 +392,7 @@ mkResult oldW oldLogs (initialRes, cpKey, cpStore, AccumState newW, newLogs) = , _observableState = oldW <> newW , _lastState = newW } - , _continuations = either (const Nothing) id initialRes + , _continuations = fromRight Nothing initialRes , _checkpointKey = cpKey } diff --git a/plutus-contract/src/Plutus/Contract/Wallet.hs b/plutus-contract/src/Plutus/Contract/Wallet.hs index e35b8750a1..721ced54dd 100644 --- a/plutus-contract/src/Plutus/Contract/Wallet.hs +++ b/plutus-contract/src/Plutus/Contract/Wallet.hs @@ -51,6 +51,7 @@ import Ledger.Constraints.OffChain (UnbalancedTx (UnbalancedTx, unBalancedTxRequ adjustUnbalancedTx, mkTx) import Ledger.Tx (CardanoTx, TxOutRef, getCardanoTxInputs, txInRef) import Plutus.Contract.CardanoAPI qualified as CardanoAPI +import Plutus.Contract.Error (AsContractError (_ConstraintResolutionContractError, _OtherContractError)) import Plutus.Contract.Request qualified as Contract import Plutus.Contract.Types (Contract) import Plutus.V1.Ledger.Scripts (MintingPolicyHash) @@ -59,7 +60,6 @@ import PlutusTx qualified import Wallet.API qualified as WAPI import Wallet.Effects (WalletEffect, balanceTx, yieldUnbalancedTx) import Wallet.Emulator.Error (WalletAPIError) -import Wallet.Types (AsContractError (_ConstraintResolutionError, _OtherError)) {- Note [Submitting transactions from Plutus contracts] @@ -110,11 +110,11 @@ getUnspentOutput :: AsContractError e => Contract w s e TxOutRef getUnspentOutput = do ownPkh <- Contract.ownPaymentPubKeyHash let constraints = mustPayToPubKey ownPkh (Ada.lovelaceValueOf 1) - utx <- either (throwing _ConstraintResolutionError) pure (mkTx @Void mempty constraints) + utx <- either (throwing _ConstraintResolutionContractError) pure (mkTx @Void mempty constraints) tx <- Contract.balanceTx (adjustUnbalancedTx utx) case Set.lookupMin (getCardanoTxInputs tx) of Just inp -> pure $ txInRef inp - Nothing -> throwing _OtherError "Balanced transaction has no inputs" + Nothing -> throwing _OtherContractError "Balanced transaction has no inputs" data ExportTxRedeemerPurpose = Spending | Minting | Rewarding diff --git a/plutus-contract/src/Plutus/Trace/Emulator/Types.hs b/plutus-contract/src/Plutus/Trace/Emulator/Types.hs index 537a30d773..8463ac39df 100644 --- a/plutus-contract/src/Plutus/Trace/Emulator/Types.hs +++ b/plutus-contract/src/Plutus/Trace/Emulator/Types.hs @@ -178,7 +178,7 @@ data ContractInstanceTag = ContractInstanceTag { unContractInstanceTag :: Text, deriving anyclass (ToJSON, FromJSON) instance NFData ContractInstanceTag where - rnf (ContractInstanceTag txt txt') = rnf txt `seq` rnf txt' `seq` () + rnf (ContractInstanceTag txt txt') = rnf txt `seq` rnf txt' instance Pretty ContractInstanceTag where pretty = pretty . shortContractInstanceTag diff --git a/plutus-contract/src/Wallet/Emulator/MultiAgent.hs b/plutus-contract/src/Wallet/Emulator/MultiAgent.hs index 24d8255959..3d38ed4b5f 100644 --- a/plutus-contract/src/Wallet/Emulator/MultiAgent.hs +++ b/plutus-contract/src/Wallet/Emulator/MultiAgent.hs @@ -39,6 +39,7 @@ import Ledger hiding (to, value) import Ledger.AddressMap qualified as AM import Ledger.Index qualified as Index import Plutus.ChainIndex.Emulator qualified as ChainIndex +import Plutus.Contract.Error (AssertionError (GenericAssertion)) import Plutus.Trace.Emulator.Types (ContractInstanceLog, EmulatedWalletEffects, EmulatedWalletEffects', UserThreadMsg) import Plutus.Trace.Scheduler qualified as Scheduler import Wallet.API qualified as WAPI @@ -47,7 +48,6 @@ import Wallet.Emulator.LogMessages (RequestHandlerLogMsg, TxBalanceMsg) import Wallet.Emulator.NodeClient qualified as NC import Wallet.Emulator.Wallet (Wallet) import Wallet.Emulator.Wallet qualified as Wallet -import Wallet.Types (AssertionError (GenericAssertion)) -- | Assertions which will be checked during execution of the emulator. data Assertion diff --git a/plutus-contract/src/Wallet/Emulator/Types.hs b/plutus-contract/src/Wallet/Emulator/Types.hs index c28a69ec60..804a629eea 100644 --- a/plutus-contract/src/Wallet/Emulator/Types.hs +++ b/plutus-contract/src/Wallet/Emulator/Types.hs @@ -32,8 +32,8 @@ module Wallet.Emulator.Types( Wallet.Emulator.MultiAgent.Assertion(OwnFundsEqual, IsValidated), Wallet.Emulator.MultiAgent.assert, Wallet.Emulator.MultiAgent.assertIsValidated, - Wallet.Types.AssertionError(..), - Wallet.Types.AsAssertionError(..), + Plutus.Contract.Error.AssertionError(..), + Plutus.Contract.Error.AsAssertionError(..), Wallet.Emulator.NodeClient.ChainClientNotification(..), Wallet.Emulator.MultiAgent.EmulatorEvent, Wallet.Emulator.MultiAgent.EmulatorEvent', @@ -80,6 +80,8 @@ import Wallet.API (WalletAPIError) import Ledger.CardanoWallet qualified import Ledger.Fee (FeeConfig) import Ledger.TimeSlot (SlotConfig) +import Plutus.Contract.Error (AssertionError) +import Plutus.Contract.Error qualified import Wallet.Emulator.Chain (ChainControlEffect, ChainEffect, ChainEvent, ChainState, handleChain, handleControlChain) import Wallet.Emulator.Chain qualified import Wallet.Emulator.MultiAgent (EmulatorEvent', EmulatorState, MultiAgentControlEffect, MultiAgentEffect, chainEvent, @@ -87,8 +89,6 @@ import Wallet.Emulator.MultiAgent (EmulatorEvent', EmulatorState, MultiAgentCont import Wallet.Emulator.MultiAgent qualified import Wallet.Emulator.NodeClient qualified import Wallet.Emulator.Wallet qualified -import Wallet.Types (AssertionError) -import Wallet.Types qualified type EmulatorEffs = '[MultiAgentEffect, ChainEffect, ChainControlEffect] diff --git a/plutus-contract/src/Wallet/Types.hs b/plutus-contract/src/Wallet/Types.hs index 9d1247ebf7..b0987019df 100644 --- a/plutus-contract/src/Wallet/Types.hs +++ b/plutus-contract/src/Wallet/Types.hs @@ -13,20 +13,11 @@ module Wallet.Types( , ContractActivityStatus(..) , parseContractActivityStatus , Notification(..) + , NotificationError(..) , EndpointDescription(..) , EndpointValue(..) - -- * Error types - , MatchingError(..) - , AsMatchingError(..) - , AssertionError(..) - , AsAssertionError(..) - , ContractError(..) - , AsContractError(..) - , NotificationError(..) - , AsNotificationError(..) ) where -import Control.Lens (prism') import Control.Lens.TH (makeClassyPrisms) import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey) import Data.Aeson qualified as Aeson @@ -42,69 +33,10 @@ import GHC.Generics (Generic) import Language.Haskell.TH.Syntax qualified as TH import Prettyprinter (Pretty (..), colon, hang, viaShow, vsep, (<+>)) -import Ledger.Constraints.OffChain (MkTxError) -import Plutus.Contract.Checkpoint (AsCheckpointError (..), CheckpointError) import Prettyprinter.Extras (PrettyShow (..), Tagged (..)) -import Wallet.Error (WalletAPIError) import Data.OpenApi.Schema qualified as OpenApi --- | An error -newtype MatchingError = WrongVariantError { unWrongVariantError :: Text } - deriving stock (Eq, Ord, Show, Generic) - deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) -makeClassyPrisms ''MatchingError -instance Pretty MatchingError where - pretty = \case - WrongVariantError t -> "Wrong variant:" <+> pretty t - --- | An error emitted when an 'Assertion' fails. -newtype AssertionError = GenericAssertion { unAssertionError :: T.Text } - deriving stock (Show, Eq, Generic) - deriving anyclass (ToJSON, FromJSON) -makeClassyPrisms ''AssertionError - -instance Pretty AssertionError where - pretty = \case - GenericAssertion t -> "Generic assertion:" <+> pretty t - --- | This lets people use 'T.Text' as their error type. -instance AsAssertionError T.Text where - _AssertionError = prism' (T.pack . show) (const Nothing) - -data ContractError = - WalletError WalletAPIError - | EmulatorAssertionError AssertionError -- TODO: Why do we need this constructor - | OtherError T.Text - | ConstraintResolutionError MkTxError - | ResumableError MatchingError - | CCheckpointError CheckpointError - deriving stock (Show, Eq, Generic) - deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) -makeClassyPrisms ''ContractError - -instance Pretty ContractError where - pretty = \case - WalletError e -> "Wallet error:" <+> pretty e - EmulatorAssertionError a -> "Emulator assertion error:" <+> pretty a - OtherError t -> "Other error:" <+> pretty t - ConstraintResolutionError e -> "Constraint resolution error:" <+> pretty e - ResumableError e -> "Resumable error:" <+> pretty e - CCheckpointError e -> "Checkpoint error:" <+> pretty e - --- | This lets people use 'T.Text' as their error type. -instance AsContractError T.Text where - _ContractError = prism' (T.pack . show) (const Nothing) - -instance IsString ContractError where - fromString = OtherError . fromString - -instance AsAssertionError ContractError where - _AssertionError = _EmulatorAssertionError - -instance AsCheckpointError ContractError where - _CheckpointError = _CCheckpointError - -- | Unique ID for contract instance newtype ContractInstanceId = ContractInstanceId { unContractInstanceId :: UUID } deriving (Eq, Ord, Show, Generic) @@ -160,8 +92,14 @@ data NotificationError = EndpointNotAvailable ContractInstanceId EndpointDescription | MoreThanOneEndpointAvailable ContractInstanceId EndpointDescription | InstanceDoesNotExist ContractInstanceId - | OtherNotificationError ContractError - | NotificationJSONDecodeError EndpointDescription Aeson.Value String -- ^ Indicates that the target contract does not have the expected schema + | NotificationJSONDecodeError EndpointDescription Aeson.Value String + -- ^ Indicates that the target contract does not have the expected schema + -- + -- TODO: SCP-2137 + -- Not currently used. As endpoint parameter decoding happends inside the Contract and + -- a throwError is used is decoding failed. + -- However, still valuable to be used by the PAB to throw an error is an endpoint + -- could not be decoded. deriving stock (Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON) @@ -170,7 +108,6 @@ instance Pretty NotificationError where EndpointNotAvailable i ep -> "Endpoint" <+> pretty ep <+> "not available on" <+> pretty i MoreThanOneEndpointAvailable i ep -> "Endpoint" <+> pretty ep <+> "is exposed more than once on" <+> pretty i InstanceDoesNotExist i -> "Instance does not exist:" <+> pretty i - OtherNotificationError e -> "Other notification error:" <+> pretty e NotificationJSONDecodeError ep vv e -> "Notification JSON decoding error:" <+> pretty e diff --git a/plutus-contract/test/Spec/Contract.hs b/plutus-contract/test/Spec/Contract.hs index 0ba1c4b1c6..06628a4dc3 100644 --- a/plutus-contract/test/Spec/Contract.hs +++ b/plutus-contract/test/Spec/Contract.hs @@ -155,9 +155,14 @@ tests = (endpointAvailable @"1" theContract tag) (void $ activateContract w1 theContract tag >>= \hdl -> callEndpoint @"1" hdl 1) - , let theContract :: Contract () Schema ContractError () = void $ throwing Con._ContractError $ OtherError "error" + , let theContract :: Contract () Schema ContractError () = + void $ throwing Con._ContractError $ OtherContractError "error" in run "throw an error" - (assertContractError theContract tag (\case { OtherError "error" -> True; _ -> False}) "failed to throw error") + (assertContractError + theContract + tag + (\case { OtherContractError "error" -> True; _ -> False }) + "failed to throw error") (void $ activateContract w1 theContract tag) , run "pay to wallet" @@ -166,7 +171,8 @@ tests = .&&. assertNoFailedTransactions) (void $ Trace.payToWallet w1 w2 (Ada.adaValueOf 20)) - , let theContract :: Contract () Schema ContractError () = void $ awaitUtxoProduced (mockWalletAddress w2) + , let theContract :: Contract () Schema ContractError () = + void $ awaitUtxoProduced (mockWalletAddress w2) in run "await utxo produced" (assertDone theContract tag (const True) "should receive a notification") (void $ do @@ -175,7 +181,10 @@ tests = Trace.waitNSlots 1 ) - , let theContract :: Contract () Schema ContractError () = void (utxosAt (mockWalletAddress w1) >>= awaitUtxoSpent . fst . head . Map.toList) + , let theContract :: Contract () Schema ContractError () = + void ( utxosAt (mockWalletAddress w1) + >>= awaitUtxoSpent . fst . head . Map.toList + ) in run "await txout spent" (assertDone theContract tag (const True) "should receive a notification") (void $ do @@ -336,7 +345,8 @@ loopCheckpointContract = do errorContract :: Contract () Schema ContractError Int errorContract = do catchError - (awaitPromise $ endpoint @"1" @Int $ \_ -> throwError (OtherError "something went wrong")) + (awaitPromise $ endpoint @"1" @Int + $ \_ -> throwError (OtherContractError "something went wrong")) (\_ -> checkpoint $ awaitPromise $ endpoint @"2" @Int pure .> endpoint @"3" @Int pure) someAddress :: Address diff --git a/plutus-pab-executables/demo/pab-nami/client/generated/Plutus/Contract/Error.purs b/plutus-pab-executables/demo/pab-nami/client/generated/Plutus/Contract/Error.purs new file mode 100644 index 0000000000..f62a5a04c8 --- /dev/null +++ b/plutus-pab-executables/demo/pab-nami/client/generated/Plutus/Contract/Error.purs @@ -0,0 +1,182 @@ +-- File auto generated by purescript-bridge! -- +module Plutus.Contract.Error where + +import Prelude + +import Control.Lazy (defer) +import Data.Argonaut (encodeJson, jsonNull) +import Data.Argonaut.Decode (class DecodeJson) +import Data.Argonaut.Decode.Aeson ((), (), ()) +import Data.Argonaut.Encode (class EncodeJson) +import Data.Argonaut.Encode.Aeson ((>$<), (>/\<)) +import Data.Generic.Rep (class Generic) +import Data.Lens (Iso', Lens', Prism', iso, prism') +import Data.Lens.Iso.Newtype (_Newtype) +import Data.Lens.Record (prop) +import Data.Maybe (Maybe(..)) +import Data.Newtype (class Newtype, unwrap) +import Data.RawJson (RawJson) +import Data.Show.Generic (genericShow) +import Data.Tuple.Nested ((/\)) +import Ledger.Constraints.OffChain (MkTxError) +import Plutus.Contract.Checkpoint (CheckpointError) +import Plutus.Contract.Effects (ChainIndexResponse) +import Type.Proxy (Proxy(Proxy)) +import Wallet.Emulator.Error (WalletAPIError) +import Wallet.Types (EndpointDescription, EndpointValue) +import Data.Argonaut.Decode.Aeson as D +import Data.Argonaut.Encode.Aeson as E +import Data.Map as Map + +newtype AssertionError = GenericAssertion { unAssertionError :: String } + +derive instance Eq AssertionError + +instance Show AssertionError where + show a = genericShow a + +instance EncodeJson AssertionError where + encodeJson = defer \_ -> E.encode $ unwrap >$< + ( E.record + { unAssertionError: E.value :: _ String } + ) + +instance DecodeJson AssertionError where + decodeJson = defer \_ -> D.decode $ (GenericAssertion <$> D.record "GenericAssertion" { unAssertionError: D.value :: _ String }) + +derive instance Generic AssertionError _ + +derive instance Newtype AssertionError _ + +-------------------------------------------------------------------------------- + +_GenericAssertion :: Iso' AssertionError { unAssertionError :: String } +_GenericAssertion = _Newtype + +-------------------------------------------------------------------------------- + +data ContractError + = WalletContractError WalletAPIError + | ChainIndexContractError String ChainIndexResponse + | EmulatorAssertionContractError AssertionError + | ConstraintResolutionContractError MkTxError + | ResumableContractError MatchingError + | CCheckpointContractError CheckpointError + | EndpointDecodeContractError + { eeEndpointDescription :: EndpointDescription + , eeEndpointValue :: EndpointValue RawJson + , eeErrorMessage :: String + } + | OtherContractError String + +derive instance Eq ContractError + +instance Show ContractError where + show a = genericShow a + +instance EncodeJson ContractError where + encodeJson = defer \_ -> case _ of + WalletContractError a -> E.encodeTagged "WalletContractError" a E.value + ChainIndexContractError a b -> E.encodeTagged "ChainIndexContractError" (a /\ b) (E.tuple (E.value >/\< E.value)) + EmulatorAssertionContractError a -> E.encodeTagged "EmulatorAssertionContractError" a E.value + ConstraintResolutionContractError a -> E.encodeTagged "ConstraintResolutionContractError" a E.value + ResumableContractError a -> E.encodeTagged "ResumableContractError" a E.value + CCheckpointContractError a -> E.encodeTagged "CCheckpointContractError" a E.value + EndpointDecodeContractError { eeEndpointDescription, eeEndpointValue, eeErrorMessage } -> encodeJson + { tag: "EndpointDecodeContractError" + , eeEndpointDescription: flip E.encode eeEndpointDescription E.value + , eeEndpointValue: flip E.encode eeEndpointValue E.value + , eeErrorMessage: flip E.encode eeErrorMessage E.value + } + OtherContractError a -> E.encodeTagged "OtherContractError" a E.value + +instance DecodeJson ContractError where + decodeJson = defer \_ -> D.decode + $ D.sumType "ContractError" + $ Map.fromFoldable + [ "WalletContractError" /\ D.content (WalletContractError <$> D.value) + , "ChainIndexContractError" /\ D.content (D.tuple $ ChainIndexContractError D.value D.value) + , "EmulatorAssertionContractError" /\ D.content (EmulatorAssertionContractError <$> D.value) + , "ConstraintResolutionContractError" /\ D.content (ConstraintResolutionContractError <$> D.value) + , "ResumableContractError" /\ D.content (ResumableContractError <$> D.value) + , "CCheckpointContractError" /\ D.content (CCheckpointContractError <$> D.value) + , "EndpointDecodeContractError" /\ + ( EndpointDecodeContractError <$> D.object "EndpointDecodeContractError" + { eeEndpointDescription: D.value :: _ EndpointDescription + , eeEndpointValue: D.value :: _ (EndpointValue RawJson) + , eeErrorMessage: D.value :: _ String + } + ) + , "OtherContractError" /\ D.content (OtherContractError <$> D.value) + ] + +derive instance Generic ContractError _ + +-------------------------------------------------------------------------------- + +_WalletContractError :: Prism' ContractError WalletAPIError +_WalletContractError = prism' WalletContractError case _ of + (WalletContractError a) -> Just a + _ -> Nothing + +_ChainIndexContractError :: Prism' ContractError { a :: String, b :: ChainIndexResponse } +_ChainIndexContractError = prism' (\{ a, b } -> (ChainIndexContractError a b)) case _ of + (ChainIndexContractError a b) -> Just { a, b } + _ -> Nothing + +_EmulatorAssertionContractError :: Prism' ContractError AssertionError +_EmulatorAssertionContractError = prism' EmulatorAssertionContractError case _ of + (EmulatorAssertionContractError a) -> Just a + _ -> Nothing + +_ConstraintResolutionContractError :: Prism' ContractError MkTxError +_ConstraintResolutionContractError = prism' ConstraintResolutionContractError case _ of + (ConstraintResolutionContractError a) -> Just a + _ -> Nothing + +_ResumableContractError :: Prism' ContractError MatchingError +_ResumableContractError = prism' ResumableContractError case _ of + (ResumableContractError a) -> Just a + _ -> Nothing + +_CCheckpointContractError :: Prism' ContractError CheckpointError +_CCheckpointContractError = prism' CCheckpointContractError case _ of + (CCheckpointContractError a) -> Just a + _ -> Nothing + +_EndpointDecodeContractError :: Prism' ContractError { eeEndpointDescription :: EndpointDescription, eeEndpointValue :: EndpointValue RawJson, eeErrorMessage :: String } +_EndpointDecodeContractError = prism' EndpointDecodeContractError case _ of + (EndpointDecodeContractError a) -> Just a + _ -> Nothing + +_OtherContractError :: Prism' ContractError String +_OtherContractError = prism' OtherContractError case _ of + (OtherContractError a) -> Just a + _ -> Nothing + +-------------------------------------------------------------------------------- + +newtype MatchingError = WrongVariantError { unWrongVariantError :: String } + +derive instance Eq MatchingError + +instance Show MatchingError where + show a = genericShow a + +instance EncodeJson MatchingError where + encodeJson = defer \_ -> E.encode $ unwrap >$< + ( E.record + { unWrongVariantError: E.value :: _ String } + ) + +instance DecodeJson MatchingError where + decodeJson = defer \_ -> D.decode $ (WrongVariantError <$> D.record "WrongVariantError" { unWrongVariantError: D.value :: _ String }) + +derive instance Generic MatchingError _ + +derive instance Newtype MatchingError _ + +-------------------------------------------------------------------------------- + +_WrongVariantError :: Iso' MatchingError { unWrongVariantError :: String } +_WrongVariantError = _Newtype diff --git a/plutus-pab-executables/demo/pab-nami/client/generated/Plutus/Contract/StateMachine.purs b/plutus-pab-executables/demo/pab-nami/client/generated/Plutus/Contract/StateMachine.purs index 40cc84e3d3..02d9cb588e 100644 --- a/plutus-pab-executables/demo/pab-nami/client/generated/Plutus/Contract/StateMachine.purs +++ b/plutus-pab-executables/demo/pab-nami/client/generated/Plutus/Contract/StateMachine.purs @@ -17,9 +17,9 @@ import Data.Maybe (Maybe(..)) import Data.Newtype (class Newtype, unwrap) import Data.Show.Generic (genericShow) import Data.Tuple.Nested ((/\)) +import Plutus.Contract.Error (ContractError) import Plutus.Contract.StateMachine.OnChain (State) import Type.Proxy (Proxy(Proxy)) -import Wallet.Types (ContractError) import Data.Argonaut.Decode.Aeson as D import Data.Argonaut.Encode.Aeson as E import Data.Map as Map diff --git a/plutus-pab-executables/demo/pab-nami/client/generated/Wallet/Types.purs b/plutus-pab-executables/demo/pab-nami/client/generated/Wallet/Types.purs index 689bad4901..b2a990bedc 100644 --- a/plutus-pab-executables/demo/pab-nami/client/generated/Wallet/Types.purs +++ b/plutus-pab-executables/demo/pab-nami/client/generated/Wallet/Types.purs @@ -22,42 +22,12 @@ import Data.RawJson (RawJson) import Data.Show.Generic (genericShow) import Data.Tuple.Nested ((/\)) import Data.UUID.Argonaut (UUID) -import Ledger.Constraints.OffChain (MkTxError) -import Plutus.Contract.Checkpoint (CheckpointError) import Servant.PureScript (class ToPathSegment, toPathSegment) import Type.Proxy (Proxy(Proxy)) -import Wallet.Emulator.Error (WalletAPIError) import Data.Argonaut.Decode.Aeson as D import Data.Argonaut.Encode.Aeson as E import Data.Map as Map -newtype AssertionError = GenericAssertion { unAssertionError :: String } - -derive instance Eq AssertionError - -instance Show AssertionError where - show a = genericShow a - -instance EncodeJson AssertionError where - encodeJson = defer \_ -> E.encode $ unwrap >$< - ( E.record - { unAssertionError: E.value :: _ String } - ) - -instance DecodeJson AssertionError where - decodeJson = defer \_ -> D.decode $ (GenericAssertion <$> D.record "GenericAssertion" { unAssertionError: D.value :: _ String }) - -derive instance Generic AssertionError _ - -derive instance Newtype AssertionError _ - --------------------------------------------------------------------------------- - -_GenericAssertion :: Iso' AssertionError { unAssertionError :: String } -_GenericAssertion = _Newtype - --------------------------------------------------------------------------------- - data ContractActivityStatus = Active | Stopped @@ -105,76 +75,6 @@ _Done = prism' (const Done) case _ of -------------------------------------------------------------------------------- -data ContractError - = WalletError WalletAPIError - | EmulatorAssertionError AssertionError - | OtherError String - | ConstraintResolutionError MkTxError - | ResumableError MatchingError - | CCheckpointError CheckpointError - -derive instance Eq ContractError - -instance Show ContractError where - show a = genericShow a - -instance EncodeJson ContractError where - encodeJson = defer \_ -> case _ of - WalletError a -> E.encodeTagged "WalletError" a E.value - EmulatorAssertionError a -> E.encodeTagged "EmulatorAssertionError" a E.value - OtherError a -> E.encodeTagged "OtherError" a E.value - ConstraintResolutionError a -> E.encodeTagged "ConstraintResolutionError" a E.value - ResumableError a -> E.encodeTagged "ResumableError" a E.value - CCheckpointError a -> E.encodeTagged "CCheckpointError" a E.value - -instance DecodeJson ContractError where - decodeJson = defer \_ -> D.decode - $ D.sumType "ContractError" - $ Map.fromFoldable - [ "WalletError" /\ D.content (WalletError <$> D.value) - , "EmulatorAssertionError" /\ D.content (EmulatorAssertionError <$> D.value) - , "OtherError" /\ D.content (OtherError <$> D.value) - , "ConstraintResolutionError" /\ D.content (ConstraintResolutionError <$> D.value) - , "ResumableError" /\ D.content (ResumableError <$> D.value) - , "CCheckpointError" /\ D.content (CCheckpointError <$> D.value) - ] - -derive instance Generic ContractError _ - --------------------------------------------------------------------------------- - -_WalletError :: Prism' ContractError WalletAPIError -_WalletError = prism' WalletError case _ of - (WalletError a) -> Just a - _ -> Nothing - -_EmulatorAssertionError :: Prism' ContractError AssertionError -_EmulatorAssertionError = prism' EmulatorAssertionError case _ of - (EmulatorAssertionError a) -> Just a - _ -> Nothing - -_OtherError :: Prism' ContractError String -_OtherError = prism' OtherError case _ of - (OtherError a) -> Just a - _ -> Nothing - -_ConstraintResolutionError :: Prism' ContractError MkTxError -_ConstraintResolutionError = prism' ConstraintResolutionError case _ of - (ConstraintResolutionError a) -> Just a - _ -> Nothing - -_ResumableError :: Prism' ContractError MatchingError -_ResumableError = prism' ResumableError case _ of - (ResumableError a) -> Just a - _ -> Nothing - -_CCheckpointError :: Prism' ContractError CheckpointError -_CCheckpointError = prism' CCheckpointError case _ of - (CCheckpointError a) -> Just a - _ -> Nothing - --------------------------------------------------------------------------------- - newtype ContractInstanceId = ContractInstanceId { unContractInstanceId :: UUID } instance ToPathSegment ContractInstanceId where @@ -263,33 +163,6 @@ _EndpointValue = _Newtype -------------------------------------------------------------------------------- -newtype MatchingError = WrongVariantError { unWrongVariantError :: String } - -derive instance Eq MatchingError - -instance Show MatchingError where - show a = genericShow a - -instance EncodeJson MatchingError where - encodeJson = defer \_ -> E.encode $ unwrap >$< - ( E.record - { unWrongVariantError: E.value :: _ String } - ) - -instance DecodeJson MatchingError where - decodeJson = defer \_ -> D.decode $ (WrongVariantError <$> D.record "WrongVariantError" { unWrongVariantError: D.value :: _ String }) - -derive instance Generic MatchingError _ - -derive instance Newtype MatchingError _ - --------------------------------------------------------------------------------- - -_WrongVariantError :: Iso' MatchingError { unWrongVariantError :: String } -_WrongVariantError = _Newtype - --------------------------------------------------------------------------------- - newtype Notification = Notification { notificationContractID :: ContractInstanceId , notificationContractEndpoint :: EndpointDescription @@ -334,7 +207,6 @@ data NotificationError = EndpointNotAvailable ContractInstanceId EndpointDescription | MoreThanOneEndpointAvailable ContractInstanceId EndpointDescription | InstanceDoesNotExist ContractInstanceId - | OtherNotificationError ContractError | NotificationJSONDecodeError EndpointDescription RawJson String derive instance Eq NotificationError @@ -347,7 +219,6 @@ instance EncodeJson NotificationError where EndpointNotAvailable a b -> E.encodeTagged "EndpointNotAvailable" (a /\ b) (E.tuple (E.value >/\< E.value)) MoreThanOneEndpointAvailable a b -> E.encodeTagged "MoreThanOneEndpointAvailable" (a /\ b) (E.tuple (E.value >/\< E.value)) InstanceDoesNotExist a -> E.encodeTagged "InstanceDoesNotExist" a E.value - OtherNotificationError a -> E.encodeTagged "OtherNotificationError" a E.value NotificationJSONDecodeError a b c -> E.encodeTagged "NotificationJSONDecodeError" (a /\ b /\ c) (E.tuple (E.value >/\< E.value >/\< E.value)) instance DecodeJson NotificationError where @@ -357,7 +228,6 @@ instance DecodeJson NotificationError where [ "EndpointNotAvailable" /\ D.content (D.tuple $ EndpointNotAvailable D.value D.value) , "MoreThanOneEndpointAvailable" /\ D.content (D.tuple $ MoreThanOneEndpointAvailable D.value D.value) , "InstanceDoesNotExist" /\ D.content (InstanceDoesNotExist <$> D.value) - , "OtherNotificationError" /\ D.content (OtherNotificationError <$> D.value) , "NotificationJSONDecodeError" /\ D.content (D.tuple $ NotificationJSONDecodeError D.value D.value D.value) ] @@ -380,11 +250,6 @@ _InstanceDoesNotExist = prism' InstanceDoesNotExist case _ of (InstanceDoesNotExist a) -> Just a _ -> Nothing -_OtherNotificationError :: Prism' NotificationError ContractError -_OtherNotificationError = prism' OtherNotificationError case _ of - (OtherNotificationError a) -> Just a - _ -> Nothing - _NotificationJSONDecodeError :: Prism' NotificationError { a :: EndpointDescription, b :: RawJson, c :: String } _NotificationJSONDecodeError = prism' (\{ a, b, c } -> (NotificationJSONDecodeError a b c)) case _ of (NotificationJSONDecodeError a b c) -> Just { a, b, c } diff --git a/plutus-playground-client/generated/Plutus/Contract/Error.purs b/plutus-playground-client/generated/Plutus/Contract/Error.purs new file mode 100644 index 0000000000..f62a5a04c8 --- /dev/null +++ b/plutus-playground-client/generated/Plutus/Contract/Error.purs @@ -0,0 +1,182 @@ +-- File auto generated by purescript-bridge! -- +module Plutus.Contract.Error where + +import Prelude + +import Control.Lazy (defer) +import Data.Argonaut (encodeJson, jsonNull) +import Data.Argonaut.Decode (class DecodeJson) +import Data.Argonaut.Decode.Aeson ((), (), ()) +import Data.Argonaut.Encode (class EncodeJson) +import Data.Argonaut.Encode.Aeson ((>$<), (>/\<)) +import Data.Generic.Rep (class Generic) +import Data.Lens (Iso', Lens', Prism', iso, prism') +import Data.Lens.Iso.Newtype (_Newtype) +import Data.Lens.Record (prop) +import Data.Maybe (Maybe(..)) +import Data.Newtype (class Newtype, unwrap) +import Data.RawJson (RawJson) +import Data.Show.Generic (genericShow) +import Data.Tuple.Nested ((/\)) +import Ledger.Constraints.OffChain (MkTxError) +import Plutus.Contract.Checkpoint (CheckpointError) +import Plutus.Contract.Effects (ChainIndexResponse) +import Type.Proxy (Proxy(Proxy)) +import Wallet.Emulator.Error (WalletAPIError) +import Wallet.Types (EndpointDescription, EndpointValue) +import Data.Argonaut.Decode.Aeson as D +import Data.Argonaut.Encode.Aeson as E +import Data.Map as Map + +newtype AssertionError = GenericAssertion { unAssertionError :: String } + +derive instance Eq AssertionError + +instance Show AssertionError where + show a = genericShow a + +instance EncodeJson AssertionError where + encodeJson = defer \_ -> E.encode $ unwrap >$< + ( E.record + { unAssertionError: E.value :: _ String } + ) + +instance DecodeJson AssertionError where + decodeJson = defer \_ -> D.decode $ (GenericAssertion <$> D.record "GenericAssertion" { unAssertionError: D.value :: _ String }) + +derive instance Generic AssertionError _ + +derive instance Newtype AssertionError _ + +-------------------------------------------------------------------------------- + +_GenericAssertion :: Iso' AssertionError { unAssertionError :: String } +_GenericAssertion = _Newtype + +-------------------------------------------------------------------------------- + +data ContractError + = WalletContractError WalletAPIError + | ChainIndexContractError String ChainIndexResponse + | EmulatorAssertionContractError AssertionError + | ConstraintResolutionContractError MkTxError + | ResumableContractError MatchingError + | CCheckpointContractError CheckpointError + | EndpointDecodeContractError + { eeEndpointDescription :: EndpointDescription + , eeEndpointValue :: EndpointValue RawJson + , eeErrorMessage :: String + } + | OtherContractError String + +derive instance Eq ContractError + +instance Show ContractError where + show a = genericShow a + +instance EncodeJson ContractError where + encodeJson = defer \_ -> case _ of + WalletContractError a -> E.encodeTagged "WalletContractError" a E.value + ChainIndexContractError a b -> E.encodeTagged "ChainIndexContractError" (a /\ b) (E.tuple (E.value >/\< E.value)) + EmulatorAssertionContractError a -> E.encodeTagged "EmulatorAssertionContractError" a E.value + ConstraintResolutionContractError a -> E.encodeTagged "ConstraintResolutionContractError" a E.value + ResumableContractError a -> E.encodeTagged "ResumableContractError" a E.value + CCheckpointContractError a -> E.encodeTagged "CCheckpointContractError" a E.value + EndpointDecodeContractError { eeEndpointDescription, eeEndpointValue, eeErrorMessage } -> encodeJson + { tag: "EndpointDecodeContractError" + , eeEndpointDescription: flip E.encode eeEndpointDescription E.value + , eeEndpointValue: flip E.encode eeEndpointValue E.value + , eeErrorMessage: flip E.encode eeErrorMessage E.value + } + OtherContractError a -> E.encodeTagged "OtherContractError" a E.value + +instance DecodeJson ContractError where + decodeJson = defer \_ -> D.decode + $ D.sumType "ContractError" + $ Map.fromFoldable + [ "WalletContractError" /\ D.content (WalletContractError <$> D.value) + , "ChainIndexContractError" /\ D.content (D.tuple $ ChainIndexContractError D.value D.value) + , "EmulatorAssertionContractError" /\ D.content (EmulatorAssertionContractError <$> D.value) + , "ConstraintResolutionContractError" /\ D.content (ConstraintResolutionContractError <$> D.value) + , "ResumableContractError" /\ D.content (ResumableContractError <$> D.value) + , "CCheckpointContractError" /\ D.content (CCheckpointContractError <$> D.value) + , "EndpointDecodeContractError" /\ + ( EndpointDecodeContractError <$> D.object "EndpointDecodeContractError" + { eeEndpointDescription: D.value :: _ EndpointDescription + , eeEndpointValue: D.value :: _ (EndpointValue RawJson) + , eeErrorMessage: D.value :: _ String + } + ) + , "OtherContractError" /\ D.content (OtherContractError <$> D.value) + ] + +derive instance Generic ContractError _ + +-------------------------------------------------------------------------------- + +_WalletContractError :: Prism' ContractError WalletAPIError +_WalletContractError = prism' WalletContractError case _ of + (WalletContractError a) -> Just a + _ -> Nothing + +_ChainIndexContractError :: Prism' ContractError { a :: String, b :: ChainIndexResponse } +_ChainIndexContractError = prism' (\{ a, b } -> (ChainIndexContractError a b)) case _ of + (ChainIndexContractError a b) -> Just { a, b } + _ -> Nothing + +_EmulatorAssertionContractError :: Prism' ContractError AssertionError +_EmulatorAssertionContractError = prism' EmulatorAssertionContractError case _ of + (EmulatorAssertionContractError a) -> Just a + _ -> Nothing + +_ConstraintResolutionContractError :: Prism' ContractError MkTxError +_ConstraintResolutionContractError = prism' ConstraintResolutionContractError case _ of + (ConstraintResolutionContractError a) -> Just a + _ -> Nothing + +_ResumableContractError :: Prism' ContractError MatchingError +_ResumableContractError = prism' ResumableContractError case _ of + (ResumableContractError a) -> Just a + _ -> Nothing + +_CCheckpointContractError :: Prism' ContractError CheckpointError +_CCheckpointContractError = prism' CCheckpointContractError case _ of + (CCheckpointContractError a) -> Just a + _ -> Nothing + +_EndpointDecodeContractError :: Prism' ContractError { eeEndpointDescription :: EndpointDescription, eeEndpointValue :: EndpointValue RawJson, eeErrorMessage :: String } +_EndpointDecodeContractError = prism' EndpointDecodeContractError case _ of + (EndpointDecodeContractError a) -> Just a + _ -> Nothing + +_OtherContractError :: Prism' ContractError String +_OtherContractError = prism' OtherContractError case _ of + (OtherContractError a) -> Just a + _ -> Nothing + +-------------------------------------------------------------------------------- + +newtype MatchingError = WrongVariantError { unWrongVariantError :: String } + +derive instance Eq MatchingError + +instance Show MatchingError where + show a = genericShow a + +instance EncodeJson MatchingError where + encodeJson = defer \_ -> E.encode $ unwrap >$< + ( E.record + { unWrongVariantError: E.value :: _ String } + ) + +instance DecodeJson MatchingError where + decodeJson = defer \_ -> D.decode $ (WrongVariantError <$> D.record "WrongVariantError" { unWrongVariantError: D.value :: _ String }) + +derive instance Generic MatchingError _ + +derive instance Newtype MatchingError _ + +-------------------------------------------------------------------------------- + +_WrongVariantError :: Iso' MatchingError { unWrongVariantError :: String } +_WrongVariantError = _Newtype diff --git a/plutus-playground-client/generated/Wallet/Types.purs b/plutus-playground-client/generated/Wallet/Types.purs index bea55b5d75..fa169a869a 100644 --- a/plutus-playground-client/generated/Wallet/Types.purs +++ b/plutus-playground-client/generated/Wallet/Types.purs @@ -22,41 +22,11 @@ import Data.RawJson (RawJson) import Data.Show.Generic (genericShow) import Data.Tuple.Nested ((/\)) import Data.UUID.Argonaut (UUID) -import Ledger.Constraints.OffChain (MkTxError) -import Plutus.Contract.Checkpoint (CheckpointError) import Type.Proxy (Proxy(Proxy)) -import Wallet.Emulator.Error (WalletAPIError) import Data.Argonaut.Decode.Aeson as D import Data.Argonaut.Encode.Aeson as E import Data.Map as Map -newtype AssertionError = GenericAssertion { unAssertionError :: String } - -derive instance Eq AssertionError - -instance Show AssertionError where - show a = genericShow a - -instance EncodeJson AssertionError where - encodeJson = defer \_ -> E.encode $ unwrap >$< - ( E.record - { unAssertionError: E.value :: _ String } - ) - -instance DecodeJson AssertionError where - decodeJson = defer \_ -> D.decode $ (GenericAssertion <$> D.record "GenericAssertion" { unAssertionError: D.value :: _ String }) - -derive instance Generic AssertionError _ - -derive instance Newtype AssertionError _ - --------------------------------------------------------------------------------- - -_GenericAssertion :: Iso' AssertionError { unAssertionError :: String } -_GenericAssertion = _Newtype - --------------------------------------------------------------------------------- - data ContractActivityStatus = Active | Stopped @@ -104,76 +74,6 @@ _Done = prism' (const Done) case _ of -------------------------------------------------------------------------------- -data ContractError - = WalletError WalletAPIError - | EmulatorAssertionError AssertionError - | OtherError String - | ConstraintResolutionError MkTxError - | ResumableError MatchingError - | CCheckpointError CheckpointError - -derive instance Eq ContractError - -instance Show ContractError where - show a = genericShow a - -instance EncodeJson ContractError where - encodeJson = defer \_ -> case _ of - WalletError a -> E.encodeTagged "WalletError" a E.value - EmulatorAssertionError a -> E.encodeTagged "EmulatorAssertionError" a E.value - OtherError a -> E.encodeTagged "OtherError" a E.value - ConstraintResolutionError a -> E.encodeTagged "ConstraintResolutionError" a E.value - ResumableError a -> E.encodeTagged "ResumableError" a E.value - CCheckpointError a -> E.encodeTagged "CCheckpointError" a E.value - -instance DecodeJson ContractError where - decodeJson = defer \_ -> D.decode - $ D.sumType "ContractError" - $ Map.fromFoldable - [ "WalletError" /\ D.content (WalletError <$> D.value) - , "EmulatorAssertionError" /\ D.content (EmulatorAssertionError <$> D.value) - , "OtherError" /\ D.content (OtherError <$> D.value) - , "ConstraintResolutionError" /\ D.content (ConstraintResolutionError <$> D.value) - , "ResumableError" /\ D.content (ResumableError <$> D.value) - , "CCheckpointError" /\ D.content (CCheckpointError <$> D.value) - ] - -derive instance Generic ContractError _ - --------------------------------------------------------------------------------- - -_WalletError :: Prism' ContractError WalletAPIError -_WalletError = prism' WalletError case _ of - (WalletError a) -> Just a - _ -> Nothing - -_EmulatorAssertionError :: Prism' ContractError AssertionError -_EmulatorAssertionError = prism' EmulatorAssertionError case _ of - (EmulatorAssertionError a) -> Just a - _ -> Nothing - -_OtherError :: Prism' ContractError String -_OtherError = prism' OtherError case _ of - (OtherError a) -> Just a - _ -> Nothing - -_ConstraintResolutionError :: Prism' ContractError MkTxError -_ConstraintResolutionError = prism' ConstraintResolutionError case _ of - (ConstraintResolutionError a) -> Just a - _ -> Nothing - -_ResumableError :: Prism' ContractError MatchingError -_ResumableError = prism' ResumableError case _ of - (ResumableError a) -> Just a - _ -> Nothing - -_CCheckpointError :: Prism' ContractError CheckpointError -_CCheckpointError = prism' CCheckpointError case _ of - (CCheckpointError a) -> Just a - _ -> Nothing - --------------------------------------------------------------------------------- - newtype ContractInstanceId = ContractInstanceId { unContractInstanceId :: UUID } derive instance Eq ContractInstanceId @@ -259,33 +159,6 @@ _EndpointValue = _Newtype -------------------------------------------------------------------------------- -newtype MatchingError = WrongVariantError { unWrongVariantError :: String } - -derive instance Eq MatchingError - -instance Show MatchingError where - show a = genericShow a - -instance EncodeJson MatchingError where - encodeJson = defer \_ -> E.encode $ unwrap >$< - ( E.record - { unWrongVariantError: E.value :: _ String } - ) - -instance DecodeJson MatchingError where - decodeJson = defer \_ -> D.decode $ (WrongVariantError <$> D.record "WrongVariantError" { unWrongVariantError: D.value :: _ String }) - -derive instance Generic MatchingError _ - -derive instance Newtype MatchingError _ - --------------------------------------------------------------------------------- - -_WrongVariantError :: Iso' MatchingError { unWrongVariantError :: String } -_WrongVariantError = _Newtype - --------------------------------------------------------------------------------- - newtype Notification = Notification { notificationContractID :: ContractInstanceId , notificationContractEndpoint :: EndpointDescription @@ -330,7 +203,6 @@ data NotificationError = EndpointNotAvailable ContractInstanceId EndpointDescription | MoreThanOneEndpointAvailable ContractInstanceId EndpointDescription | InstanceDoesNotExist ContractInstanceId - | OtherNotificationError ContractError | NotificationJSONDecodeError EndpointDescription RawJson String derive instance Eq NotificationError @@ -343,7 +215,6 @@ instance EncodeJson NotificationError where EndpointNotAvailable a b -> E.encodeTagged "EndpointNotAvailable" (a /\ b) (E.tuple (E.value >/\< E.value)) MoreThanOneEndpointAvailable a b -> E.encodeTagged "MoreThanOneEndpointAvailable" (a /\ b) (E.tuple (E.value >/\< E.value)) InstanceDoesNotExist a -> E.encodeTagged "InstanceDoesNotExist" a E.value - OtherNotificationError a -> E.encodeTagged "OtherNotificationError" a E.value NotificationJSONDecodeError a b c -> E.encodeTagged "NotificationJSONDecodeError" (a /\ b /\ c) (E.tuple (E.value >/\< E.value >/\< E.value)) instance DecodeJson NotificationError where @@ -353,7 +224,6 @@ instance DecodeJson NotificationError where [ "EndpointNotAvailable" /\ D.content (D.tuple $ EndpointNotAvailable D.value D.value) , "MoreThanOneEndpointAvailable" /\ D.content (D.tuple $ MoreThanOneEndpointAvailable D.value D.value) , "InstanceDoesNotExist" /\ D.content (InstanceDoesNotExist <$> D.value) - , "OtherNotificationError" /\ D.content (OtherNotificationError <$> D.value) , "NotificationJSONDecodeError" /\ D.content (D.tuple $ NotificationJSONDecodeError D.value D.value D.value) ] @@ -376,11 +246,6 @@ _InstanceDoesNotExist = prism' InstanceDoesNotExist case _ of (InstanceDoesNotExist a) -> Just a _ -> Nothing -_OtherNotificationError :: Prism' NotificationError ContractError -_OtherNotificationError = prism' OtherNotificationError case _ of - (OtherNotificationError a) -> Just a - _ -> Nothing - _NotificationJSONDecodeError :: Prism' NotificationError { a :: EndpointDescription, b :: RawJson, c :: String } _NotificationJSONDecodeError = prism' (\{ a, b, c } -> (NotificationJSONDecodeError a b c)) case _ of (NotificationJSONDecodeError a b c) -> Just { a, b, c } diff --git a/plutus-use-cases/src/Plutus/Contracts/TokenAccount.hs b/plutus-use-cases/src/Plutus/Contracts/TokenAccount.hs index 726d8d699a..1899c13021 100644 --- a/plutus-use-cases/src/Plutus/Contracts/TokenAccount.hs +++ b/plutus-use-cases/src/Plutus/Contracts/TokenAccount.hs @@ -37,16 +37,16 @@ module Plutus.Contracts.TokenAccount( , typedValidator ) where -import Control.Lens +import Control.Lens (makeClassyPrisms, review, view) import Control.Monad (void) -import Control.Monad.Error.Lens import Data.Aeson (FromJSON, ToJSON) import Data.Map qualified as Map import GHC.Generics (Generic) -import Prettyprinter +import Prettyprinter (Pretty) -import Plutus.Contract -import Plutus.Contract.Constraints +import Plutus.Contract (AsContractError (_ContractError), Contract, ContractError, Endpoint, HasEndpoint, endpoint, + logInfo, mapError, mkTxConstraints, selectList, submitUnbalancedTx, type (.\/), utxosAt) +import Plutus.Contract.Constraints (ScriptLookups, TxConstraints) import PlutusTx qualified import Ledger (Address, PaymentPubKeyHash, ValidatorHash) @@ -55,15 +55,14 @@ import Ledger.Constraints qualified as Constraints import Ledger.Contexts qualified as V import Ledger.Scripts qualified import Ledger.Tx (CardanoTx) -import Ledger.Typed.Scripts (ValidatorTypes (..)) +import Ledger.Typed.Scripts (ValidatorTypes) import Ledger.Typed.Scripts qualified as Scripts import Ledger.Value (TokenName, Value) import Ledger.Value qualified as Value import Plutus.Contract.Typed.Tx qualified as TypedTx - import Plutus.Contracts.Currency qualified as Currency -import Prettyprinter.Extras (PrettyShow (..)) +import Prettyprinter.Extras (PrettyShow (PrettyShow)) newtype Account = Account { accountOwner :: Value.AssetClass } deriving stock (Eq, Show, Generic) @@ -202,10 +201,8 @@ redeem -> Contract w s e CardanoTx redeem pk account = mapError (review _TokenAccountError) $ do (constraints, lookups) <- redeemTx account pk - utx <- either (throwing _ConstraintResolutionError) - (pure . Constraints.adjustUnbalancedTx) - (Constraints.mkTx lookups constraints) - submitUnbalancedTx utx + utx <- mkTxConstraints lookups constraints + submitUnbalancedTx $ Constraints.adjustUnbalancedTx utx -- | @balance account@ returns the value of all unspent outputs that can be -- unlocked with @accountToken account@ diff --git a/plutus-use-cases/test/Spec/contractError.txt b/plutus-use-cases/test/Spec/contractError.txt index ca22695c37..24d1711279 100644 --- a/plutus-use-cases/test/Spec/contractError.txt +++ b/plutus-use-cases/test/Spec/contractError.txt @@ -1,4 +1,4 @@ Slot 1: 00000000-0000-4000-8000-000000000000 {Wallet W872c}: Contract instance started Slot 1: 00000000-0000-4000-8000-000000000000 {Wallet W872c}: - Contract instance stopped with error: OtherError "something went wrong" \ No newline at end of file + Contract instance stopped with error: OtherContractError "something went wrong" \ No newline at end of file