{-# OPTIONS_GHC -Wno-orphans #-}

-- | This module defines convenient wrappers for mock chain wallets (around
-- Plutus mock wallets) with an associate API to construct them, manipulate
-- them, and fetch information (such as public/private and staking keys).
module Cooked.Wallet
  ( knownWallets,
    wallet,
    walletPKHashToId,
    walletPKHashToWallet,
    walletPK,
    walletStakingPK,
    walletPKHash,
    walletStakingPKHash,
    walletAddress,
    walletSK,
    walletStakingSK,
    walletStakingCredential,
    walletCredential,
    Wallet,
    PrivateKey,
  )
where

import Cardano.Crypto.Wallet qualified as Crypto
import Data.Function (on)
import Data.List (elemIndex)
import Ledger.Address qualified as Ledger
import Ledger.CardanoWallet qualified as Ledger
import Ledger.Crypto qualified as Ledger
import PlutusLedgerApi.V3 qualified as Api

-- * MockChain Wallets

-- $mockchainwallets
--
-- Because mock wallets from plutus-ledger change often, we provide our own
-- wrapper on top of them to ensure that we can easily deal changes from Plutus.

type Wallet = Ledger.MockWallet

type PrivateKey = Crypto.XPrv

instance Eq Wallet where
  == :: Wallet -> Wallet -> Bool
(==) = Digest Blake2b_160 -> Digest Blake2b_160 -> Bool
forall a. Eq a => a -> a -> Bool
(==) (Digest Blake2b_160 -> Digest Blake2b_160 -> Bool)
-> (Wallet -> Digest Blake2b_160) -> Wallet -> Wallet -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Wallet -> Digest Blake2b_160
Ledger.mwWalletId

instance Ord Wallet where
  compare :: Wallet -> Wallet -> Ordering
compare = Digest Blake2b_160 -> Digest Blake2b_160 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Digest Blake2b_160 -> Digest Blake2b_160 -> Ordering)
-> (Wallet -> Digest Blake2b_160) -> Wallet -> Wallet -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Wallet -> Digest Blake2b_160
Ledger.mwWalletId

-- | All the wallets corresponding to known Plutus mock wallets. This is a list
-- of 10 wallets which will
--
-- - receive funds in the standard initial distribution of cooked-validators,
--
-- - be pretty-printed as part the final state after running a few transactions.
knownWallets :: [Wallet]
knownWallets :: [Wallet]
knownWallets = [Wallet]
Ledger.knownMockWallets

-- | Wallet corresponding to a given wallet number (or wallet ID) with an offset
-- of 1 to start at 1 instead of 0
wallet :: Integer -> Wallet
wallet :: Integer -> Wallet
wallet Integer
j
  | Integer
j Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
0 Bool -> Bool -> Bool
&& Integer
j Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
10 = Integer -> Wallet
Ledger.knownMockWallet Integer
j
  | Bool
otherwise = WalletNumber -> Wallet
Ledger.fromWalletNumber (WalletNumber -> Wallet) -> WalletNumber -> Wallet
forall a b. (a -> b) -> a -> b
$ Integer -> WalletNumber
Ledger.WalletNumber Integer
j

-- | Retrieves the id of the known wallet that corresponds to a public key hash
--
-- @walletPKHashToId (walletPKHash (wallet 3)) == Just 3@
walletPKHashToId :: Api.PubKeyHash -> Maybe Int
walletPKHashToId :: PubKeyHash -> Maybe Int
walletPKHashToId = (Int -> Int
forall a. Enum a => a -> a
succ (Int -> Int) -> Maybe Int -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Maybe Int -> Maybe Int)
-> (PubKeyHash -> Maybe Int) -> PubKeyHash -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PubKeyHash -> [PubKeyHash] -> Maybe Int)
-> [PubKeyHash] -> PubKeyHash -> Maybe Int
forall a b c. (a -> b -> c) -> b -> a -> c
flip PubKeyHash -> [PubKeyHash] -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
elemIndex (Wallet -> PubKeyHash
walletPKHash (Wallet -> PubKeyHash) -> [Wallet] -> [PubKeyHash]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Wallet]
knownWallets)

-- | Retrieves the known wallet that corresponds to a public key hash
walletPKHashToWallet :: Api.PubKeyHash -> Maybe Wallet
walletPKHashToWallet :: PubKeyHash -> Maybe Wallet
walletPKHashToWallet PubKeyHash
pkh = Integer -> Wallet
wallet (Integer -> Wallet) -> (Int -> Integer) -> Int -> Wallet
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Wallet) -> Maybe Int -> Maybe Wallet
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> PubKeyHash -> Maybe Int
walletPKHashToId PubKeyHash
pkh

-- | Retrieves a wallet public key (PK)
walletPK :: Wallet -> Ledger.PubKey
walletPK :: Wallet -> PubKey
walletPK = PaymentPubKey -> PubKey
Ledger.unPaymentPubKey (PaymentPubKey -> PubKey)
-> (Wallet -> PaymentPubKey) -> Wallet -> PubKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Wallet -> PaymentPubKey
Ledger.paymentPubKey

-- | Retrieves a wallet's public staking key (PK), if any
walletStakingPK :: Wallet -> Maybe Ledger.PubKey
walletStakingPK :: Wallet -> Maybe PubKey
walletStakingPK = (XPrv -> PubKey) -> Maybe XPrv -> Maybe PubKey
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap XPrv -> PubKey
Ledger.toPublicKey (Maybe XPrv -> Maybe PubKey)
-> (Wallet -> Maybe XPrv) -> Wallet -> Maybe PubKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Wallet -> Maybe XPrv
walletStakingSK

-- | Retrieves a wallet's public key hash
walletPKHash :: Wallet -> Api.PubKeyHash
walletPKHash :: Wallet -> PubKeyHash
walletPKHash = PubKey -> PubKeyHash
Ledger.pubKeyHash (PubKey -> PubKeyHash)
-> (Wallet -> PubKey) -> Wallet -> PubKeyHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Wallet -> PubKey
walletPK

-- | Retrieves a wallet's public staking key hash, if any
walletStakingPKHash :: Wallet -> Maybe Api.PubKeyHash
walletStakingPKHash :: Wallet -> Maybe PubKeyHash
walletStakingPKHash = (PubKey -> PubKeyHash) -> Maybe PubKey -> Maybe PubKeyHash
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap PubKey -> PubKeyHash
Ledger.pubKeyHash (Maybe PubKey -> Maybe PubKeyHash)
-> (Wallet -> Maybe PubKey) -> Wallet -> Maybe PubKeyHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Wallet -> Maybe PubKey
walletStakingPK

-- | Retrieves a wallet credential
walletCredential :: Wallet -> Api.Credential
walletCredential :: Wallet -> Credential
walletCredential = PubKeyHash -> Credential
Api.PubKeyCredential (PubKeyHash -> Credential)
-> (Wallet -> PubKeyHash) -> Wallet -> Credential
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Wallet -> PubKeyHash
walletPKHash

walletStakingCredential :: Wallet -> Maybe Api.StakingCredential
walletStakingCredential :: Wallet -> Maybe StakingCredential
walletStakingCredential = (Credential -> StakingCredential
Api.StakingHash (Credential -> StakingCredential)
-> (PubKeyHash -> Credential) -> PubKeyHash -> StakingCredential
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PubKeyHash -> Credential
Api.PubKeyCredential (PubKeyHash -> StakingCredential)
-> Maybe PubKeyHash -> Maybe StakingCredential
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Maybe PubKeyHash -> Maybe StakingCredential)
-> (Wallet -> Maybe PubKeyHash)
-> Wallet
-> Maybe StakingCredential
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Wallet -> Maybe PubKeyHash
walletStakingPKHash

-- | Retrieves a wallet's address
walletAddress :: Wallet -> Api.Address
walletAddress :: Wallet -> Address
walletAddress Wallet
w =
  Credential -> Maybe StakingCredential -> Address
Api.Address
    (PubKeyHash -> Credential
Api.PubKeyCredential (PubKeyHash -> Credential) -> PubKeyHash -> Credential
forall a b. (a -> b) -> a -> b
$ Wallet -> PubKeyHash
walletPKHash Wallet
w)
    (Credential -> StakingCredential
Api.StakingHash (Credential -> StakingCredential)
-> (PubKeyHash -> Credential) -> PubKeyHash -> StakingCredential
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PubKeyHash -> Credential
Api.PubKeyCredential (PubKeyHash -> StakingCredential)
-> Maybe PubKeyHash -> Maybe StakingCredential
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Wallet -> Maybe PubKeyHash
walletStakingPKHash Wallet
w)

-- | Retrieves a wallet private key (secret key SK)
walletSK :: Wallet -> PrivateKey
walletSK :: Wallet -> XPrv
walletSK = PaymentPrivateKey -> XPrv
Ledger.unPaymentPrivateKey (PaymentPrivateKey -> XPrv)
-> (Wallet -> PaymentPrivateKey) -> Wallet -> XPrv
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Wallet -> PaymentPrivateKey
Ledger.paymentPrivateKey

-- | Retrieves a wallet's private staking key (secret key SK), if any
walletStakingSK :: Wallet -> Maybe PrivateKey
walletStakingSK :: Wallet -> Maybe XPrv
walletStakingSK = (StakePrivateKey -> XPrv) -> Maybe StakePrivateKey -> Maybe XPrv
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap StakePrivateKey -> XPrv
Ledger.unStakePrivateKey (Maybe StakePrivateKey -> Maybe XPrv)
-> (Wallet -> Maybe StakePrivateKey) -> Wallet -> Maybe XPrv
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Wallet -> Maybe StakePrivateKey
Ledger.stakePrivateKey