-- | This module exposes the notion of user used everywhere in our
-- 'Cooked.Skeleton.TxSkel'. A user can either be a script or a pubkey, and
-- might be used in a redemption or an allocation setting. All of this is
-- grouped under a single data type. Typically, users should rarely be created
-- by hands, and instead, smart constructors adapted to the user's location in
-- the skeleton should be used.
module Cooked.Skeleton.User
  ( -- * Aliases
    VScript,
    ToVScript,
    toVScript,

    -- * Data types
    UserMode (..),
    UserKind (..),
    User (..),
    Peer,

    -- * Optics
    userHashG,
    userCredentialG,
    userTxSkelRedeemerAT,
    userVScriptAT,
    userScriptHashAF,
    userPubKeyHashAT,
    userPubKeyHashI,
    userVScriptL,
    userScriptHashG,
    userTxSkelRedeemerL,
    userEitherScriptP,
    userEitherPubKeyP,
    userTypedAF,
    userTypedScriptAT,
    userTypedPubKeyAT,
  )
where

import Cooked.Skeleton.Families
import Cooked.Skeleton.Redeemer
import Data.Kind
import Data.Typeable
import Optics.Core
import Plutus.Script.Utils.Address qualified as Script
import Plutus.Script.Utils.Scripts qualified as Script
import PlutusLedgerApi.V3 qualified as Api

-- * Handy aliases around versioned scripts

-- | 'VScript' is a convenient alias as we have versioned scripts everywhere.
type VScript = Script.Versioned Script.Script

-- | The 'ToVScript' alias will come in handy when dealing with constrains.
type ToVScript = Script.ToVersioned Script.Script

-- | The 'toVScript' alias will come in handy to default the type parameter of
-- 'Script.toVersioned' to 'Script.Script'.
toVScript :: (ToVScript script) => script -> VScript
toVScript :: forall script. ToVScript script => script -> VScript
toVScript = script -> VScript
forall s a. ToVersioned s a => a -> Versioned s
Script.toVersioned

-- * A depiction of user kinds and modes

-- | The 'UserMode' corresponds to the way the user will be used in our
-- 'Cooked.Skeleton.TxSkel' which can either be for allocation (allocation a
-- certain entity to a user) or for redemption (using this user as a witness in
-- a transaction).
data UserMode = Allocation | Redemption
  deriving (UserMode -> UserMode -> Bool
(UserMode -> UserMode -> Bool)
-> (UserMode -> UserMode -> Bool) -> Eq UserMode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: UserMode -> UserMode -> Bool
== :: UserMode -> UserMode -> Bool
$c/= :: UserMode -> UserMode -> Bool
/= :: UserMode -> UserMode -> Bool
Eq, Int -> UserMode -> ShowS
[UserMode] -> ShowS
UserMode -> String
(Int -> UserMode -> ShowS)
-> (UserMode -> String) -> ([UserMode] -> ShowS) -> Show UserMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> UserMode -> ShowS
showsPrec :: Int -> UserMode -> ShowS
$cshow :: UserMode -> String
show :: UserMode -> String
$cshowList :: [UserMode] -> ShowS
showList :: [UserMode] -> ShowS
Show)

-- | The 'UserKind' corresponds to the requirement on the type of users. Some
-- elements will require specifically a script and some others a pubkey.
data UserKind = IsScript | IsPubKey | IsEither | IsNone
  deriving (UserKind -> UserKind -> Bool
(UserKind -> UserKind -> Bool)
-> (UserKind -> UserKind -> Bool) -> Eq UserKind
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: UserKind -> UserKind -> Bool
== :: UserKind -> UserKind -> Bool
$c/= :: UserKind -> UserKind -> Bool
/= :: UserKind -> UserKind -> Bool
Eq, Int -> UserKind -> ShowS
[UserKind] -> ShowS
UserKind -> String
(Int -> UserKind -> ShowS)
-> (UserKind -> String) -> ([UserKind] -> ShowS) -> Show UserKind
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> UserKind -> ShowS
showsPrec :: Int -> UserKind -> ShowS
$cshow :: UserKind -> String
show :: UserKind -> String
$cshowList :: [UserKind] -> ShowS
showList :: [UserKind] -> ShowS
Show)

-- * Users, with their kind and mode

-- | Building users. The type exposes the mode for which the user has been
-- built, and the requirements on the kind of the user.
data User :: UserKind -> UserMode -> Type where
  -- | A pubkey user. This can be used whenever a pubkey is needed, and for
  -- either of the possible modes.
  UserPubKey :: forall pkh kind mode. (kind  '[IsPubKey, IsEither], Script.ToPubKeyHash pkh, Typeable pkh) => pkh -> User kind mode
  -- | A script user. This can be used whenever a script is needed, but only for
  -- the allocation mode.
  UserScript :: forall script kind. (kind  '[IsScript, IsEither], ToVScript script, Typeable script) => script -> User kind Allocation
  -- | A script user with an associated redeemer. This can be used whenever a
  -- script is needed for redemption mode.
  UserRedeemedScript :: forall script kind. (kind  [IsScript, IsEither], ToVScript script, Typeable script) => script -> TxSkelRedeemer -> User kind Redemption

-- | An alias for 'User IsPubKey Allocation'
type Peer = User IsPubKey Allocation

instance Show (User kind mode) where
  show :: User kind mode -> String
show (UserPubKey (pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash -> PubKeyHash
pkh)) = String
"UserPubKey " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> PubKeyHash -> String
forall a. Show a => a -> String
show PubKeyHash
pkh
  show (UserScript (script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> VScript
vScript)) = String
"UserScript " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> ScriptHash -> String
forall a. Show a => a -> String
show (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash VScript
vScript)
  show (UserRedeemedScript (script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> VScript
vScript) TxSkelRedeemer
red) = String
"UserRedeemedScript " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> ScriptHash -> String
forall a. Show a => a -> String
show (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash VScript
vScript) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> TxSkelRedeemer -> String
forall a. Show a => a -> String
show TxSkelRedeemer
red

instance Eq (User kind mode) where
  (UserPubKey (pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash -> PubKeyHash
pkh)) == :: User kind mode -> User kind mode -> Bool
== (UserPubKey (pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash -> PubKeyHash
pkh')) =
    PubKeyHash
pkh PubKeyHash -> PubKeyHash -> Bool
forall a. Eq a => a -> a -> Bool
== PubKeyHash
pkh'
  (UserScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> ScriptHash
sHash)) == (UserScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> ScriptHash
sHash')) =
    ScriptHash
sHash ScriptHash -> ScriptHash -> Bool
forall a. Eq a => a -> a -> Bool
== ScriptHash
sHash'
  (UserRedeemedScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> ScriptHash
sHash) TxSkelRedeemer
red) == (UserRedeemedScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> ScriptHash
sHash') TxSkelRedeemer
red') =
    ScriptHash
sHash ScriptHash -> ScriptHash -> Bool
forall a. Eq a => a -> a -> Bool
== ScriptHash
sHash' Bool -> Bool -> Bool
&& TxSkelRedeemer
red TxSkelRedeemer -> TxSkelRedeemer -> Bool
forall a. Eq a => a -> a -> Bool
== TxSkelRedeemer
red'
  User kind mode
_ == User kind mode
_ = Bool
False

instance Ord (User kind mode) where
  compare :: User kind mode -> User kind mode -> Ordering
compare (UserPubKey {}) (UserScript {}) = Ordering
LT
  compare (UserPubKey {}) (UserRedeemedScript {}) = Ordering
LT
  compare (UserScript {}) (UserPubKey {}) = Ordering
GT
  compare (UserRedeemedScript {}) (UserPubKey {}) = Ordering
GT
  compare (UserPubKey (pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash -> PubKeyHash
pkh)) (UserPubKey (pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash -> PubKeyHash
pkh')) = PubKeyHash -> PubKeyHash -> Ordering
forall a. Ord a => a -> a -> Ordering
compare PubKeyHash
pkh PubKeyHash
pkh'
  compare (UserScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> ScriptHash
sh)) (UserScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> ScriptHash
sh')) = ScriptHash -> ScriptHash -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ScriptHash
sh ScriptHash
sh'
  compare (UserRedeemedScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> ScriptHash
sh) TxSkelRedeemer
red) (UserRedeemedScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> ScriptHash
sh') TxSkelRedeemer
red') =
    (ScriptHash, TxSkelRedeemer)
-> (ScriptHash, TxSkelRedeemer) -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (ScriptHash
sh, TxSkelRedeemer
red) (ScriptHash
sh', TxSkelRedeemer
red')

instance Script.ToPubKeyHash (User IsPubKey mode) where
  toPubKeyHash :: User 'IsPubKey mode -> PubKeyHash
toPubKeyHash = Optic' An_Iso NoIx (User 'IsPubKey mode) PubKeyHash
-> User 'IsPubKey mode -> PubKeyHash
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' An_Iso NoIx (User 'IsPubKey mode) PubKeyHash
forall (mode :: UserMode). Iso' (User 'IsPubKey mode) PubKeyHash
userPubKeyHashI

instance Script.ToCredential (User kind mode) where
  toCredential :: User kind mode -> Credential
toCredential (UserPubKey (pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash -> PubKeyHash
pkh)) = PubKeyHash -> Credential
forall a. ToCredential a => a -> Credential
Script.toCredential PubKeyHash
pkh
  toCredential (UserScript (script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> VScript
vScript)) = VScript -> Credential
forall a. ToCredential a => a -> Credential
Script.toCredential VScript
vScript
  toCredential (UserRedeemedScript (script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> VScript
vScript) TxSkelRedeemer
_) = VScript -> Credential
forall a. ToCredential a => a -> Credential
Script.toCredential VScript
vScript

instance Script.ToAddress (User kind mode) where
  toAddress :: User kind mode -> Address
toAddress User kind mode
user = Credential -> Maybe StakingCredential -> Address
Api.Address (User kind mode -> Credential
forall a. ToCredential a => a -> Credential
Script.toCredential User kind mode
user) Maybe StakingCredential
forall a. Maybe a
Nothing

-- * Optics on various possible families of users

-- | Retrieves the hash of the script or pubkey represented by this user
userHashG :: forall kind mode. Getter (User kind mode) Api.BuiltinByteString
userHashG :: forall (kind :: UserKind) (mode :: UserMode).
Getter (User kind mode) BuiltinByteString
userHashG =
  (User kind mode -> BuiltinByteString)
-> Getter (User kind mode) BuiltinByteString
forall s a. (s -> a) -> Getter s a
to
    ( \case
        UserPubKey (pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash -> Api.PubKeyHash BuiltinByteString
hs) -> BuiltinByteString
hs
        UserScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> Api.ScriptHash BuiltinByteString
hs) -> BuiltinByteString
hs
        UserRedeemedScript (VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash (VScript -> ScriptHash)
-> (script -> VScript) -> script -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> Api.ScriptHash BuiltinByteString
hs) TxSkelRedeemer
_ -> BuiltinByteString
hs
    )

-- | Retrieves a possible typed user from a 'User'
userTypedAF :: forall user kind mode. (Typeable user) => AffineFold (User kind mode) user
userTypedAF :: forall user (kind :: UserKind) (mode :: UserMode).
Typeable user =>
AffineFold (User kind mode) user
userTypedAF =
  (User kind mode -> Maybe user) -> AffineFold (User kind mode) user
forall s a. (s -> Maybe a) -> AffineFold s a
afolding
    ( \case
        UserPubKey @user' pkh
pkh | Just user :~: pkh
Refl <- forall {k} (a :: k) (b :: k).
(Typeable a, Typeable b) =>
Maybe (a :~: b)
forall a b. (Typeable a, Typeable b) => Maybe (a :~: b)
eqT @user @user' -> user -> Maybe user
forall a. a -> Maybe a
Just user
pkh
pkh
        UserScript @user' script
script | Just user :~: script
Refl <- forall {k} (a :: k) (b :: k).
(Typeable a, Typeable b) =>
Maybe (a :~: b)
forall a b. (Typeable a, Typeable b) => Maybe (a :~: b)
eqT @user @user' -> user -> Maybe user
forall a. a -> Maybe a
Just user
script
script
        UserRedeemedScript @user' script
script TxSkelRedeemer
_ | Just user :~: script
Refl <- forall {k} (a :: k) (b :: k).
(Typeable a, Typeable b) =>
Maybe (a :~: b)
forall a b. (Typeable a, Typeable b) => Maybe (a :~: b)
eqT @user @user' -> user -> Maybe user
forall a. a -> Maybe a
Just user
script
script
        User kind mode
_ -> Maybe user
forall a. Maybe a
Nothing
    )

-- | Focuses on a possible typed script in this 'User'
userTypedScriptAT :: forall userScript mode. (ToVScript userScript, Typeable userScript) => AffineTraversal' (User IsScript mode) userScript
userTypedScriptAT :: forall userScript (mode :: UserMode).
(ToVScript userScript, Typeable userScript) =>
AffineTraversal' (User 'IsScript mode) userScript
userTypedScriptAT =
  (User 'IsScript mode -> Either (User 'IsScript mode) userScript)
-> (User 'IsScript mode -> userScript -> User 'IsScript mode)
-> AffineTraversal
     (User 'IsScript mode) (User 'IsScript mode) userScript userScript
forall s t a b.
(s -> Either t a) -> (s -> b -> t) -> AffineTraversal s t a b
atraversal
    ( \User 'IsScript mode
user -> case User 'IsScript mode
user of
        UserScript @userScript' script
script | Just userScript :~: script
Refl <- forall {k} (a :: k) (b :: k).
(Typeable a, Typeable b) =>
Maybe (a :~: b)
forall a b. (Typeable a, Typeable b) => Maybe (a :~: b)
eqT @userScript @userScript' -> userScript -> Either (User 'IsScript mode) userScript
forall a b. b -> Either a b
Right userScript
script
script
        UserRedeemedScript @userScript' script
script TxSkelRedeemer
_ | Just userScript :~: script
Refl <- forall {k} (a :: k) (b :: k).
(Typeable a, Typeable b) =>
Maybe (a :~: b)
forall a b. (Typeable a, Typeable b) => Maybe (a :~: b)
eqT @userScript @userScript' -> userScript -> Either (User 'IsScript mode) userScript
forall a b. b -> Either a b
Right userScript
script
script
        User 'IsScript mode
_ -> User 'IsScript mode -> Either (User 'IsScript mode) userScript
forall a b. a -> Either a b
Left User 'IsScript mode
user
    )
    ( \case
        UserScript script
_ -> userScript -> User 'IsScript mode
userScript -> User 'IsScript 'Allocation
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> User kind 'Allocation
UserScript
        UserRedeemedScript script
_ TxSkelRedeemer
red -> (userScript -> TxSkelRedeemer -> User 'IsScript 'Redemption
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> TxSkelRedeemer -> User kind 'Redemption
`UserRedeemedScript` TxSkelRedeemer
red)
    )

-- | Focuses on a possible typed pubkey in this 'User'
userTypedPubKeyAT :: forall userPK mode. (Script.ToPubKeyHash userPK, Typeable userPK) => AffineTraversal' (User IsPubKey mode) userPK
userTypedPubKeyAT :: forall userPK (mode :: UserMode).
(ToPubKeyHash userPK, Typeable userPK) =>
AffineTraversal' (User 'IsPubKey mode) userPK
userTypedPubKeyAT =
  (User 'IsPubKey mode -> Either (User 'IsPubKey mode) userPK)
-> (User 'IsPubKey mode -> userPK -> User 'IsPubKey mode)
-> AffineTraversal
     (User 'IsPubKey mode) (User 'IsPubKey mode) userPK userPK
forall s t a b.
(s -> Either t a) -> (s -> b -> t) -> AffineTraversal s t a b
atraversal
    ( \User 'IsPubKey mode
user -> case User 'IsPubKey mode
user of
        UserPubKey @userPK' pkh
pkh | Just userPK :~: pkh
Refl <- forall {k} (a :: k) (b :: k).
(Typeable a, Typeable b) =>
Maybe (a :~: b)
forall a b. (Typeable a, Typeable b) => Maybe (a :~: b)
eqT @userPK @userPK' -> userPK -> Either (User 'IsPubKey mode) userPK
forall a b. b -> Either a b
Right userPK
pkh
pkh
        User 'IsPubKey mode
_ -> User 'IsPubKey mode -> Either (User 'IsPubKey mode) userPK
forall a b. a -> Either a b
Left User 'IsPubKey mode
user
    )
    (\(UserPubKey pkh
_) -> userPK -> User 'IsPubKey mode
forall pkh (kind :: UserKind) (mode :: UserMode).
(kind ∈ '[ 'IsPubKey, 'IsEither], ToPubKeyHash pkh,
 Typeable pkh) =>
pkh -> User kind mode
UserPubKey)

-- | Builds a @User IsEither@ from a @User IsScript@
userEitherScriptP :: Prism' (User IsEither mode) (User IsScript mode)
userEitherScriptP :: forall (mode :: UserMode).
Prism' (User 'IsEither mode) (User 'IsScript mode)
userEitherScriptP =
  (User 'IsScript mode -> User 'IsEither mode)
-> (User 'IsEither mode
    -> Either (User 'IsEither mode) (User 'IsScript mode))
-> Prism
     (User 'IsEither mode)
     (User 'IsEither mode)
     (User 'IsScript mode)
     (User 'IsScript mode)
forall b t s a. (b -> t) -> (s -> Either t a) -> Prism s t a b
prism
    ( \case
        UserScript script
script -> script -> User 'IsEither 'Allocation
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> User kind 'Allocation
UserScript script
script
        UserRedeemedScript script
script TxSkelRedeemer
red -> script -> TxSkelRedeemer -> User 'IsEither 'Redemption
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> TxSkelRedeemer -> User kind 'Redemption
UserRedeemedScript script
script TxSkelRedeemer
red
    )
    ( \case
        UserScript script
script -> User 'IsScript mode
-> Either (User 'IsEither mode) (User 'IsScript mode)
forall a b. b -> Either a b
Right (script -> User 'IsScript 'Allocation
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> User kind 'Allocation
UserScript script
script)
        UserRedeemedScript script
script TxSkelRedeemer
red -> User 'IsScript mode
-> Either (User 'IsEither mode) (User 'IsScript mode)
forall a b. b -> Either a b
Right (script -> TxSkelRedeemer -> User 'IsScript 'Redemption
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> TxSkelRedeemer -> User kind 'Redemption
UserRedeemedScript script
script TxSkelRedeemer
red)
        User 'IsEither mode
user -> User 'IsEither mode
-> Either (User 'IsEither mode) (User 'IsScript mode)
forall a b. a -> Either a b
Left User 'IsEither mode
user
    )

-- | Builds a @User IsEither@ from a @User IsPubKey@
userEitherPubKeyP :: Prism' (User IsEither mode) (User IsPubKey mode)
userEitherPubKeyP :: forall (mode :: UserMode).
Prism' (User 'IsEither mode) (User 'IsPubKey mode)
userEitherPubKeyP =
  (User 'IsPubKey mode -> User 'IsEither mode)
-> (User 'IsEither mode
    -> Either (User 'IsEither mode) (User 'IsPubKey mode))
-> Prism
     (User 'IsEither mode)
     (User 'IsEither mode)
     (User 'IsPubKey mode)
     (User 'IsPubKey mode)
forall b t s a. (b -> t) -> (s -> Either t a) -> Prism s t a b
prism
    (\(UserPubKey pkh
pkh) -> pkh -> User 'IsEither mode
forall pkh (kind :: UserKind) (mode :: UserMode).
(kind ∈ '[ 'IsPubKey, 'IsEither], ToPubKeyHash pkh,
 Typeable pkh) =>
pkh -> User kind mode
UserPubKey pkh
pkh)
    ( \case
        UserPubKey pkh
pkh -> User 'IsPubKey mode
-> Either (User 'IsEither mode) (User 'IsPubKey mode)
forall a b. b -> Either a b
Right (pkh -> User 'IsPubKey mode
forall pkh (kind :: UserKind) (mode :: UserMode).
(kind ∈ '[ 'IsPubKey, 'IsEither], ToPubKeyHash pkh,
 Typeable pkh) =>
pkh -> User kind mode
UserPubKey pkh
pkh)
        User 'IsEither mode
user -> User 'IsEither mode
-> Either (User 'IsEither mode) (User 'IsPubKey mode)
forall a b. a -> Either a b
Left User 'IsEither mode
user
    )

-- | Extracts the 'Api.Credential' from a 'User'
userCredentialG :: Getter (User kind mode) Api.Credential
userCredentialG :: forall (kind :: UserKind) (mode :: UserMode).
Getter (User kind mode) Credential
userCredentialG = (User kind mode -> Credential)
-> Getter (User kind mode) Credential
forall s a. (s -> a) -> Getter s a
to User kind mode -> Credential
forall a. ToCredential a => a -> Credential
Script.toCredential

-- | Focusing on the possible 'TxSkelRedeemer' of this 'User'
userTxSkelRedeemerAT :: AffineTraversal' (User kind mode) TxSkelRedeemer
userTxSkelRedeemerAT :: forall (kind :: UserKind) (mode :: UserMode).
AffineTraversal' (User kind mode) TxSkelRedeemer
userTxSkelRedeemerAT =
  (User kind mode -> Either (User kind mode) TxSkelRedeemer)
-> (User kind mode -> TxSkelRedeemer -> User kind mode)
-> AffineTraversal
     (User kind mode) (User kind mode) TxSkelRedeemer TxSkelRedeemer
forall s t a b.
(s -> Either t a) -> (s -> b -> t) -> AffineTraversal s t a b
atraversal
    ( \case
        UserRedeemedScript script
_ TxSkelRedeemer
red -> TxSkelRedeemer -> Either (User kind mode) TxSkelRedeemer
forall a b. b -> Either a b
Right TxSkelRedeemer
red
        User kind mode
user -> User kind mode -> Either (User kind mode) TxSkelRedeemer
forall a b. a -> Either a b
Left User kind mode
user
    )
    ( \case
        UserRedeemedScript script
script TxSkelRedeemer
_ -> script -> TxSkelRedeemer -> User kind 'Redemption
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> TxSkelRedeemer -> User kind 'Redemption
UserRedeemedScript script
script
        User kind mode
user -> User kind mode -> TxSkelRedeemer -> User kind mode
forall a b. a -> b -> a
const User kind mode
user
    )

-- | Focusing on the possible 'VScript' of this 'User'
userVScriptAT :: AffineTraversal' (User kind mode) VScript
userVScriptAT :: forall (kind :: UserKind) (mode :: UserMode).
AffineTraversal' (User kind mode) VScript
userVScriptAT =
  (User kind mode -> Either (User kind mode) VScript)
-> (User kind mode -> VScript -> User kind mode)
-> AffineTraversal
     (User kind mode) (User kind mode) VScript VScript
forall s t a b.
(s -> Either t a) -> (s -> b -> t) -> AffineTraversal s t a b
atraversal
    ( \case
        UserScript (script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> VScript
vScript) -> VScript -> Either (User kind mode) VScript
forall a b. b -> Either a b
Right VScript
vScript
        UserRedeemedScript (script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> VScript
vScript) TxSkelRedeemer
_ -> VScript -> Either (User kind mode) VScript
forall a b. b -> Either a b
Right VScript
vScript
        User kind mode
user -> User kind mode -> Either (User kind mode) VScript
forall a b. a -> Either a b
Left User kind mode
user
    )
    ( \case
        UserScript script
_ -> VScript -> User kind mode
VScript -> User kind 'Allocation
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> User kind 'Allocation
UserScript
        UserRedeemedScript script
_ TxSkelRedeemer
red -> (VScript -> TxSkelRedeemer -> User kind 'Redemption
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> TxSkelRedeemer -> User kind 'Redemption
`UserRedeemedScript` TxSkelRedeemer
red)
        User kind mode
user -> User kind mode -> VScript -> User kind mode
forall a b. a -> b -> a
const User kind mode
user
    )

-- | Focusing on the possible 'Api.ScriptHash' of this 'User'
userScriptHashAF :: AffineFold (User kind mode) Api.ScriptHash
userScriptHashAF :: forall (kind :: UserKind) (mode :: UserMode).
AffineFold (User kind mode) ScriptHash
userScriptHashAF = AffineTraversal' (User kind mode) VScript
forall (kind :: UserKind) (mode :: UserMode).
AffineTraversal' (User kind mode) VScript
userVScriptAT AffineTraversal' (User kind mode) VScript
-> Optic A_Getter NoIx VScript VScript ScriptHash ScriptHash
-> Optic
     An_AffineFold
     NoIx
     (User kind mode)
     (User kind mode)
     ScriptHash
     ScriptHash
forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% (VScript -> ScriptHash)
-> Optic A_Getter NoIx VScript VScript ScriptHash ScriptHash
forall s a. (s -> a) -> Getter s a
to VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash

-- | Focusing on the possible 'Api.PubKeyHash' of this 'User'
userPubKeyHashAT :: AffineTraversal' (User kind mode) Api.PubKeyHash
userPubKeyHashAT :: forall (kind :: UserKind) (mode :: UserMode).
AffineTraversal' (User kind mode) PubKeyHash
userPubKeyHashAT =
  (User kind mode -> Either (User kind mode) PubKeyHash)
-> (User kind mode -> PubKeyHash -> User kind mode)
-> AffineTraversal
     (User kind mode) (User kind mode) PubKeyHash PubKeyHash
forall s t a b.
(s -> Either t a) -> (s -> b -> t) -> AffineTraversal s t a b
atraversal
    ( \case
        UserPubKey (pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash -> PubKeyHash
pkh) -> PubKeyHash -> Either (User kind mode) PubKeyHash
forall a b. b -> Either a b
Right PubKeyHash
pkh
        User kind mode
user -> User kind mode -> Either (User kind mode) PubKeyHash
forall a b. a -> Either a b
Left User kind mode
user
    )
    ( \case
        UserPubKey pkh
_ -> PubKeyHash -> User kind mode
forall pkh (kind :: UserKind) (mode :: UserMode).
(kind ∈ '[ 'IsPubKey, 'IsEither], ToPubKeyHash pkh,
 Typeable pkh) =>
pkh -> User kind mode
UserPubKey
        User kind mode
user -> User kind mode -> PubKeyHash -> User kind mode
forall a b. a -> b -> a
const User kind mode
user
    )

-- | An isomorphism between users required to be pubkeys and 'Api.PubKeyHash'
userPubKeyHashI :: Iso' (User IsPubKey mode) Api.PubKeyHash
userPubKeyHashI :: forall (mode :: UserMode). Iso' (User 'IsPubKey mode) PubKeyHash
userPubKeyHashI =
  (User 'IsPubKey mode -> PubKeyHash)
-> (PubKeyHash -> User 'IsPubKey mode)
-> Iso
     (User 'IsPubKey mode) (User 'IsPubKey mode) PubKeyHash PubKeyHash
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso
    (\(UserPubKey (pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash -> PubKeyHash
pkh)) -> PubKeyHash
pkh)
    PubKeyHash -> User 'IsPubKey mode
forall pkh (kind :: UserKind) (mode :: UserMode).
(kind ∈ '[ 'IsPubKey, 'IsEither], ToPubKeyHash pkh,
 Typeable pkh) =>
pkh -> User kind mode
UserPubKey

-- | Focusing on the 'VScript' from a script
userVScriptL :: Lens' (User IsScript mode) VScript
userVScriptL :: forall (mode :: UserMode). Lens' (User 'IsScript mode) VScript
userVScriptL =
  (User 'IsScript mode -> VScript)
-> (User 'IsScript mode -> VScript -> User 'IsScript mode)
-> Lens (User 'IsScript mode) (User 'IsScript mode) VScript VScript
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens
    ( \case
        UserScript (script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> VScript
vScript) -> VScript
vScript
        UserRedeemedScript (script -> VScript
forall script. ToVScript script => script -> VScript
toVScript -> VScript
vScript) TxSkelRedeemer
_ -> VScript
vScript
    )
    ( \case
        UserScript script
_ -> VScript -> User 'IsScript mode
VScript -> User 'IsScript 'Allocation
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> User kind 'Allocation
UserScript
        UserRedeemedScript script
_ TxSkelRedeemer
red -> (VScript -> TxSkelRedeemer -> User 'IsScript 'Redemption
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> TxSkelRedeemer -> User kind 'Redemption
`UserRedeemedScript` TxSkelRedeemer
red)
    )

-- | Focusing on the 'Api.ScriptHash' from a script
userScriptHashG :: Getter (User IsScript mode) Api.ScriptHash
userScriptHashG :: forall (mode :: UserMode). Getter (User 'IsScript mode) ScriptHash
userScriptHashG = Lens' (User 'IsScript mode) VScript
forall (mode :: UserMode). Lens' (User 'IsScript mode) VScript
userVScriptL Lens' (User 'IsScript mode) VScript
-> Optic A_Getter NoIx VScript VScript ScriptHash ScriptHash
-> Optic
     A_Getter
     NoIx
     (User 'IsScript mode)
     (User 'IsScript mode)
     ScriptHash
     ScriptHash
forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% (VScript -> ScriptHash)
-> Optic A_Getter NoIx VScript VScript ScriptHash ScriptHash
forall s a. (s -> a) -> Getter s a
to VScript -> ScriptHash
forall a. ToScriptHash a => a -> ScriptHash
Script.toScriptHash

-- | Focus on the 'TxSkelRedeemer' from a script being redeemed
userTxSkelRedeemerL :: Lens' (User IsScript Redemption) TxSkelRedeemer
userTxSkelRedeemerL :: Lens' (User 'IsScript 'Redemption) TxSkelRedeemer
userTxSkelRedeemerL =
  (User 'IsScript 'Redemption -> TxSkelRedeemer)
-> (User 'IsScript 'Redemption
    -> TxSkelRedeemer -> User 'IsScript 'Redemption)
-> Lens' (User 'IsScript 'Redemption) TxSkelRedeemer
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens
    (\(UserRedeemedScript script
_ TxSkelRedeemer
red) -> TxSkelRedeemer
red)
    (\(UserRedeemedScript script
script TxSkelRedeemer
_) -> script -> TxSkelRedeemer -> User 'IsScript 'Redemption
forall pkh (kind :: UserKind).
(kind ∈ '[ 'IsScript, 'IsEither], ToVScript pkh, Typeable pkh) =>
pkh -> TxSkelRedeemer -> User kind 'Redemption
UserRedeemedScript script
script)