-- | This module exposes the notion of signatory for out 'Cooked.Skeleton.TxSkel'
module Cooked.Skeleton.Signatory
  ( -- * Data types
    TxSkelSignatory (..),

    -- * Optics
    txSkelSignatoryMPrivateKeyL,
    txSkelSignatoryPrivateKeyAT,
    txSkelSignatoryPubKeyHashL,

    -- * Smart constructors
    signatoryWallet,
    signatoryPubKey,
    txSkelSignatoriesFromList,
  )
where

import Cardano.Crypto.Wallet qualified as Crypto
import Cooked.Wallet
import Optics.Core
import Optics.TH
import Plutus.Script.Utils.V3 qualified as Script
import PlutusLedgerApi.V3 qualified as Api

-- | Signatories in skeletons
data TxSkelSignatory where
  TxSkelSignatory ::
    (Script.ToPubKeyHash pkh, Show pkh) =>
    { -- | Identifying the signatory with their pubkey hash
      ()
txSkelSignatoryPubKeyHash :: pkh,
      -- | The private key with which this signatory should sign. If set to
      -- @Nothing@ the signature won't be added (but will be needed later on).oiu clairement
      TxSkelSignatory -> Maybe XPrv
txSkelSignatoryPrivateKey :: Maybe Crypto.XPrv
    } ->
    TxSkelSignatory

-- | A lens focusing on the option private key for this signatory
makeLensesFor [("txSkelSignatoryPrivateKey", "txSkelSignatoryMPrivateKeyL")] ''TxSkelSignatory

-- | An affine traversal focusing on the existing private key for this signatory
txSkelSignatoryPrivateKeyAT :: AffineTraversal' TxSkelSignatory Crypto.XPrv
txSkelSignatoryPrivateKeyAT :: AffineTraversal' TxSkelSignatory XPrv
txSkelSignatoryPrivateKeyAT = Lens' TxSkelSignatory (Maybe XPrv)
txSkelSignatoryMPrivateKeyL Lens' TxSkelSignatory (Maybe XPrv)
-> Optic A_Prism NoIx (Maybe XPrv) (Maybe XPrv) XPrv XPrv
-> AffineTraversal' TxSkelSignatory XPrv
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
% Optic A_Prism NoIx (Maybe XPrv) (Maybe XPrv) XPrv XPrv
forall a b. Prism (Maybe a) (Maybe b) a b
_Just

-- | A lens focusing on the public key hash of this signatory
txSkelSignatoryPubKeyHashL :: Lens' TxSkelSignatory Api.PubKeyHash
txSkelSignatoryPubKeyHashL :: Lens' TxSkelSignatory PubKeyHash
txSkelSignatoryPubKeyHashL =
  (TxSkelSignatory -> PubKeyHash)
-> (TxSkelSignatory -> PubKeyHash -> TxSkelSignatory)
-> Lens' TxSkelSignatory PubKeyHash
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens
    (\(TxSkelSignatory pkh
pkh Maybe XPrv
_) -> pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash pkh
pkh)
    (\TxSkelSignatory
sig PubKeyHash
pkh -> TxSkelSignatory
sig {txSkelSignatoryPubKeyHash = pkh})

instance Show TxSkelSignatory where
  show :: TxSkelSignatory -> String
show (TxSkelSignatory pkh
pkh Maybe XPrv
Nothing) = String
"Only pubkey hash: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> pkh -> String
forall a. Show a => a -> String
show pkh
pkh
  show (TxSkelSignatory pkh
pkh (Just XPrv
_)) = String
"Pubkey hash: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> pkh -> String
forall a. Show a => a -> String
show pkh
pkh String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" accompanied by a private key."

instance Eq TxSkelSignatory where
  (TxSkelSignatory pkh
pkh Maybe XPrv
sk) == :: TxSkelSignatory -> TxSkelSignatory -> Bool
== (TxSkelSignatory pkh
pkh1 Maybe XPrv
sk1) =
    pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash pkh
pkh PubKeyHash -> PubKeyHash -> Bool
forall a. Eq a => a -> a -> Bool
== pkh -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash pkh
pkh1
      Bool -> Bool -> Bool
&& ((XPrv -> ByteString) -> Maybe XPrv -> Maybe ByteString
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap XPrv -> ByteString
Crypto.unXPrv Maybe XPrv
sk Maybe ByteString -> Maybe ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== (XPrv -> ByteString) -> Maybe XPrv -> Maybe ByteString
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap XPrv -> ByteString
Crypto.unXPrv Maybe XPrv
sk1)

instance Script.ToPubKeyHash TxSkelSignatory where
  toPubKeyHash :: TxSkelSignatory -> PubKeyHash
toPubKeyHash = Lens' TxSkelSignatory PubKeyHash -> TxSkelSignatory -> PubKeyHash
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Lens' TxSkelSignatory PubKeyHash
txSkelSignatoryPubKeyHashL

-- | Builds a signatory from a wallet, which will be able to actually sign the
-- transaction.
signatoryWallet :: Wallet -> TxSkelSignatory
signatoryWallet :: Wallet -> TxSkelSignatory
signatoryWallet Wallet
w = PubKeyHash -> Maybe XPrv -> TxSkelSignatory
forall pkh.
(ToPubKeyHash pkh, Show pkh) =>
pkh -> Maybe XPrv -> TxSkelSignatory
TxSkelSignatory (Wallet -> PubKeyHash
forall a. ToPubKeyHash a => a -> PubKeyHash
Script.toPubKeyHash Wallet
w) (XPrv -> Maybe XPrv
forall a. a -> Maybe a
Just (XPrv -> Maybe XPrv) -> XPrv -> Maybe XPrv
forall a b. (a -> b) -> a -> b
$ Wallet -> XPrv
walletSK Wallet
w)

-- | Builds a signatory from a pubkey, which will no be able to actually sign
-- the transaction, but will act as a requirement.
signatoryPubKey :: (Script.ToPubKeyHash pkh, Show pkh) => pkh -> TxSkelSignatory
signatoryPubKey :: forall pkh. (ToPubKeyHash pkh, Show pkh) => pkh -> TxSkelSignatory
signatoryPubKey = (pkh -> Maybe XPrv -> TxSkelSignatory
forall pkh.
(ToPubKeyHash pkh, Show pkh) =>
pkh -> Maybe XPrv -> TxSkelSignatory
`TxSkelSignatory` Maybe XPrv
forall a. Maybe a
Nothing)

-- | Builds a list of signatories from a list of wallets
txSkelSignatoriesFromList :: [Wallet] -> [TxSkelSignatory]
txSkelSignatoriesFromList :: [Wallet] -> [TxSkelSignatory]
txSkelSignatoriesFromList = (Wallet -> TxSkelSignatory) -> [Wallet] -> [TxSkelSignatory]
forall a b. (a -> b) -> [a] -> [b]
map Wallet -> TxSkelSignatory
signatoryWallet