-- | This module provides a convenient framework to look through UTxOs and
-- search relevant ones based on predicates. For instance, it makes it very
-- convenient to gather all UTxOs at a certain address.
module Cooked.MockChain.UtxoSearch
  ( UtxoSearch,
    runUtxoSearch,
    allUtxosSearch,
    utxosAtSearch,
    utxosFromCardanoTxSearch,
    txOutByRefSearch,
    filterWith,
    filterWithPure,
    filterWithOptic,
    filterWithPred,
    filterWithValuePred,
    filterWithOnlyAda,
    filterWithNotOnlyAda,
    onlyValueOutputsAtSearch,
    vanillaOutputsAtSearch,
    filterWithAlways,
    scriptOutputsSearch,
    referenceScriptOutputsSearch,
  )
where

import Control.Monad
import Cooked.MockChain.BlockChain
import Cooked.Output
import Data.Maybe
import Ledger.Tx qualified as Ledger
import ListT (ListT (..))
import ListT qualified
import Optics.Core
import Plutus.Script.Utils.Address qualified as Script
import Plutus.Script.Utils.Scripts qualified as Script
import PlutusLedgerApi.V1.Value qualified as Api
import PlutusLedgerApi.V3 qualified as Api

-- * The type of UTxO searches

-- | If a UTxO is a 'Api.TxOutRef' with some additional information, this type
-- captures a "stream" of UTxOs.
type UtxoSearch m a = ListT m (Api.TxOutRef, a)

-- | Given a UTxO search, we can run it to obtain a list of UTxOs.
runUtxoSearch :: (Monad m) => UtxoSearch m a -> m [(Api.TxOutRef, a)]
runUtxoSearch :: forall (m :: * -> *) a.
Monad m =>
UtxoSearch m a -> m [(TxOutRef, a)]
runUtxoSearch = ListT m (TxOutRef, a) -> m [(TxOutRef, a)]
forall (m :: * -> *) a. Monad m => ListT m a -> m [a]
ListT.toList

-- * Initial UTxO searches

-- | Search all currently known 'Api.TxOutRef's together with their corresponding
-- 'Api.TxOut'.
allUtxosSearch :: (MonadBlockChain m) => UtxoSearch m Api.TxOut
allUtxosSearch :: forall (m :: * -> *). MonadBlockChain m => UtxoSearch m TxOut
allUtxosSearch = ListT m [(TxOutRef, TxOut)]
forall (m :: * -> *).
MonadBlockChainWithoutValidation m =>
m [(TxOutRef, TxOut)]
allUtxos ListT m [(TxOutRef, TxOut)]
-> ([(TxOutRef, TxOut)] -> ListT m (TxOutRef, TxOut))
-> ListT m (TxOutRef, TxOut)
forall a b. ListT m a -> (a -> ListT m b) -> ListT m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [(TxOutRef, TxOut)] -> ListT m (TxOutRef, TxOut)
forall (m :: * -> *) (f :: * -> *) a.
(Monad m, Foldable f) =>
f a -> ListT m a
ListT.fromFoldable

-- | Search all 'Api.TxOutRef's at a certain address, together with their
-- 'Api.TxOut'.
utxosAtSearch :: (MonadBlockChainBalancing m, Script.ToAddress addr) => addr -> UtxoSearch m Api.TxOut
utxosAtSearch :: forall (m :: * -> *) addr.
(MonadBlockChainBalancing m, ToAddress addr) =>
addr -> UtxoSearch m TxOut
utxosAtSearch = Address -> ListT m [(TxOutRef, TxOut)]
forall (m :: * -> *).
MonadBlockChainBalancing m =>
Address -> m [(TxOutRef, TxOut)]
utxosAt (Address -> ListT m [(TxOutRef, TxOut)])
-> (addr -> Address) -> addr -> ListT m [(TxOutRef, TxOut)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. addr -> Address
forall a. ToAddress a => a -> Address
Script.toAddress (addr -> ListT m [(TxOutRef, TxOut)])
-> ([(TxOutRef, TxOut)] -> ListT m (TxOutRef, TxOut))
-> addr
-> ListT m (TxOutRef, TxOut)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> [(TxOutRef, TxOut)] -> ListT m (TxOutRef, TxOut)
forall (m :: * -> *) (f :: * -> *) a.
(Monad m, Foldable f) =>
f a -> ListT m a
ListT.fromFoldable

-- | Search all 'Api.TxOutRef's of a transaction, together with their
-- 'Api.TxOut'.
utxosFromCardanoTxSearch :: (Monad m) => Ledger.CardanoTx -> UtxoSearch m Api.TxOut
utxosFromCardanoTxSearch :: forall (m :: * -> *). Monad m => CardanoTx -> UtxoSearch m TxOut
utxosFromCardanoTxSearch = [(TxOutRef, TxOut)] -> ListT m (TxOutRef, TxOut)
forall (m :: * -> *) (f :: * -> *) a.
(Monad m, Foldable f) =>
f a -> ListT m a
ListT.fromFoldable ([(TxOutRef, TxOut)] -> ListT m (TxOutRef, TxOut))
-> (CardanoTx -> [(TxOutRef, TxOut)])
-> CardanoTx
-> ListT m (TxOutRef, TxOut)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CardanoTx -> [(TxOutRef, TxOut)]
utxosFromCardanoTx

-- | Search all 'Api.TxOut's corresponding to given the list of
-- 'Api.TxOutRef's. Any 'Api.TxOutRef' that doesn't correspond to a known output
-- will be filtered out.
txOutByRefSearch :: (MonadBlockChainBalancing m) => [Api.TxOutRef] -> UtxoSearch m Api.TxOut
txOutByRefSearch :: forall (m :: * -> *).
MonadBlockChainBalancing m =>
[TxOutRef] -> UtxoSearch m TxOut
txOutByRefSearch [TxOutRef]
orefs =
  (TxOutRef -> m (TxOutRef, TxOutRef))
-> ListT m TxOutRef -> ListT m (TxOutRef, TxOutRef)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> ListT m a -> ListT m b
ListT.traverse (\TxOutRef
o -> (TxOutRef, TxOutRef) -> m (TxOutRef, TxOutRef)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (TxOutRef
o, TxOutRef
o)) ([TxOutRef] -> ListT m TxOutRef
forall (m :: * -> *) (f :: * -> *) a.
(Monad m, Foldable f) =>
f a -> ListT m a
ListT.fromFoldable [TxOutRef]
orefs)
    ListT m (TxOutRef, TxOutRef)
-> (TxOutRef -> m (Maybe TxOut)) -> UtxoSearch m TxOut
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> m (Maybe b)) -> UtxoSearch m b
`filterWith` TxOutRef -> m (Maybe TxOut)
forall (m :: * -> *).
MonadBlockChainBalancing m =>
TxOutRef -> m (Maybe TxOut)
txOutByRef

-- * filtering UTxO searches

-- | Transform a 'UtxoSearch' by applying a possibly partial monadic
-- transformation on each output in the stream
filterWith :: (Monad m) => UtxoSearch m a -> (a -> m (Maybe b)) -> UtxoSearch m b
filterWith :: forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> m (Maybe b)) -> UtxoSearch m b
filterWith (ListT m (Maybe ((TxOutRef, a), ListT m (TxOutRef, a)))
as) a -> m (Maybe b)
f =
  m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
-> ListT m (TxOutRef, b)
forall (m :: * -> *) a. m (Maybe (a, ListT m a)) -> ListT m a
ListT (m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
 -> ListT m (TxOutRef, b))
-> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
-> ListT m (TxOutRef, b)
forall a b. (a -> b) -> a -> b
$
    m (Maybe ((TxOutRef, a), ListT m (TxOutRef, a)))
as m (Maybe ((TxOutRef, a), ListT m (TxOutRef, a)))
-> (Maybe ((TxOutRef, a), ListT m (TxOutRef, a))
    -> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b))))
-> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Maybe ((TxOutRef, a), ListT m (TxOutRef, a))
Nothing -> Maybe ((TxOutRef, b), ListT m (TxOutRef, b))
-> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ((TxOutRef, b), ListT m (TxOutRef, b))
forall a. Maybe a
Nothing
      Just ((TxOutRef
oref, a
a), ListT m (TxOutRef, a)
rest) ->
        let filteredRest :: ListT m (TxOutRef, b)
filteredRest@(ListT m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
bs) = ListT m (TxOutRef, a)
-> (a -> m (Maybe b)) -> ListT m (TxOutRef, b)
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> m (Maybe b)) -> UtxoSearch m b
filterWith ListT m (TxOutRef, a)
rest a -> m (Maybe b)
f
         in a -> m (Maybe b)
f a
a m (Maybe b)
-> (Maybe b -> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b))))
-> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
              Maybe b
Nothing -> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
bs
              Just b
b -> Maybe ((TxOutRef, b), ListT m (TxOutRef, b))
-> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe ((TxOutRef, b), ListT m (TxOutRef, b))
 -> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b))))
-> Maybe ((TxOutRef, b), ListT m (TxOutRef, b))
-> m (Maybe ((TxOutRef, b), ListT m (TxOutRef, b)))
forall a b. (a -> b) -> a -> b
$ ((TxOutRef, b), ListT m (TxOutRef, b))
-> Maybe ((TxOutRef, b), ListT m (TxOutRef, b))
forall a. a -> Maybe a
Just ((TxOutRef
oref, b
b), ListT m (TxOutRef, b)
filteredRest)

-- | Same as 'filterWith' but with a pure transformation
filterWithPure :: (Monad m) => UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
filterWithPure :: forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
filterWithPure UtxoSearch m a
as a -> Maybe b
f = UtxoSearch m a -> (a -> m (Maybe b)) -> UtxoSearch m b
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> m (Maybe b)) -> UtxoSearch m b
filterWith UtxoSearch m a
as (Maybe b -> m (Maybe b)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe b -> m (Maybe b)) -> (a -> Maybe b) -> a -> m (Maybe b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Maybe b
f)

-- | Some as 'filterWithPure' but with a total transformation
filterWithAlways :: (Monad m) => UtxoSearch m a -> (a -> b) -> UtxoSearch m b
filterWithAlways :: forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> b) -> UtxoSearch m b
filterWithAlways UtxoSearch m a
as a -> b
f = UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
filterWithPure UtxoSearch m a
as (b -> Maybe b
forall a. a -> Maybe a
Just (b -> Maybe b) -> (a -> b) -> a -> Maybe b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
f)

-- | Some as 'filterWithPure', but the transformation is taken from an optic
filterWithOptic :: (Is k An_AffineFold, Monad m) => UtxoSearch m a -> Optic' k is a b -> UtxoSearch m b
filterWithOptic :: forall k (m :: * -> *) a (is :: IxList) b.
(Is k An_AffineFold, Monad m) =>
UtxoSearch m a -> Optic' k is a b -> UtxoSearch m b
filterWithOptic UtxoSearch m a
as Optic' k is a b
optic = UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
filterWithPure UtxoSearch m a
as (a -> Optic' k is a b -> Maybe b
forall k s (is :: IxList) a.
Is k An_AffineFold =>
s -> Optic' k is s a -> Maybe a
^? Optic' k is a b
optic)

-- | Same as 'filterWithPure' but the outputs are selected using a boolean
-- predicate, and not modified
filterWithPred :: (Monad m) => UtxoSearch m a -> (a -> Bool) -> UtxoSearch m a
filterWithPred :: forall (m :: * -> *) a.
Monad m =>
UtxoSearch m a -> (a -> Bool) -> UtxoSearch m a
filterWithPred UtxoSearch m a
as a -> Bool
f = UtxoSearch m a -> (a -> Maybe a) -> UtxoSearch m a
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
filterWithPure UtxoSearch m a
as ((a -> Maybe a) -> UtxoSearch m a)
-> (a -> Maybe a) -> UtxoSearch m a
forall a b. (a -> b) -> a -> b
$ \a
a -> if a -> Bool
f a
a then a -> Maybe a
forall a. a -> Maybe a
Just a
a else Maybe a
forall a. Maybe a
Nothing

-- | A specific version of 'filterWithPred' where outputs must me of type
-- 'Api.TxOut' and the predicate only relies on their value
filterWithValuePred :: (Monad m) => UtxoSearch m Api.TxOut -> (Api.Value -> Bool) -> UtxoSearch m Api.Value
filterWithValuePred :: forall (m :: * -> *).
Monad m =>
UtxoSearch m TxOut -> (Value -> Bool) -> UtxoSearch m Value
filterWithValuePred UtxoSearch m TxOut
as = UtxoSearch m Value -> (Value -> Bool) -> UtxoSearch m Value
forall (m :: * -> *) a.
Monad m =>
UtxoSearch m a -> (a -> Bool) -> UtxoSearch m a
filterWithPred (UtxoSearch m TxOut -> (TxOut -> Value) -> UtxoSearch m Value
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> b) -> UtxoSearch m b
filterWithAlways UtxoSearch m TxOut
as TxOut -> Value
Api.txOutValue)

-- | A specific version of 'filterWithValuePred' when 'Api.TxOut's are only kept
-- when they contain only ADA
filterWithOnlyAda :: (Monad m) => UtxoSearch m Api.TxOut -> UtxoSearch m Api.Value
filterWithOnlyAda :: forall (m :: * -> *).
Monad m =>
UtxoSearch m TxOut -> UtxoSearch m Value
filterWithOnlyAda UtxoSearch m TxOut
as = UtxoSearch m TxOut -> (Value -> Bool) -> UtxoSearch m Value
forall (m :: * -> *).
Monad m =>
UtxoSearch m TxOut -> (Value -> Bool) -> UtxoSearch m Value
filterWithValuePred UtxoSearch m TxOut
as ((Value -> Bool) -> UtxoSearch m Value)
-> (Value -> Bool) -> UtxoSearch m Value
forall a b. (a -> b) -> a -> b
$ (Int
1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
==) (Int -> Bool) -> (Value -> Int) -> Value -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(CurrencySymbol, TokenName, Integer)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([(CurrencySymbol, TokenName, Integer)] -> Int)
-> (Value -> [(CurrencySymbol, TokenName, Integer)])
-> Value
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> [(CurrencySymbol, TokenName, Integer)]
Api.flattenValue

-- | A specific version of 'filterWithValuePred' when 'Api.TxOut's are only kept
-- when they contain non-ADA assets
filterWithNotOnlyAda :: (Monad m) => UtxoSearch m Api.TxOut -> UtxoSearch m Api.Value
filterWithNotOnlyAda :: forall (m :: * -> *).
Monad m =>
UtxoSearch m TxOut -> UtxoSearch m Value
filterWithNotOnlyAda UtxoSearch m TxOut
as = UtxoSearch m TxOut -> (Value -> Bool) -> UtxoSearch m Value
forall (m :: * -> *).
Monad m =>
UtxoSearch m TxOut -> (Value -> Bool) -> UtxoSearch m Value
filterWithValuePred UtxoSearch m TxOut
as ((Value -> Bool) -> UtxoSearch m Value)
-> (Value -> Bool) -> UtxoSearch m Value
forall a b. (a -> b) -> a -> b
$ (Int
1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<) (Int -> Bool) -> (Value -> Int) -> Value -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(CurrencySymbol, TokenName, Integer)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([(CurrencySymbol, TokenName, Integer)] -> Int)
-> (Value -> [(CurrencySymbol, TokenName, Integer)])
-> Value
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> [(CurrencySymbol, TokenName, Integer)]
Api.flattenValue

-- * Useful composite UTxO searches with filters already applied

-- | Search for UTxOs at a specific address, which only carry address and value
-- information (no datum, staking credential, or reference script).
onlyValueOutputsAtSearch ::
  (MonadBlockChainBalancing m, Script.ToAddress addr) =>
  addr ->
  UtxoSearch m (ConcreteOutput Api.Credential () Api.Value Api.ScriptHash)
onlyValueOutputsAtSearch :: forall (m :: * -> *) addr.
(MonadBlockChainBalancing m, ToAddress addr) =>
addr
-> UtxoSearch m (ConcreteOutput Credential () Value ScriptHash)
onlyValueOutputsAtSearch addr
addr =
  addr -> UtxoSearch m TxOut
forall (m :: * -> *) addr.
(MonadBlockChainBalancing m, ToAddress addr) =>
addr -> UtxoSearch m TxOut
utxosAtSearch addr
addr
    UtxoSearch m TxOut
-> (TxOut
    -> ConcreteOutput Credential OutputDatum Value ScriptHash)
-> UtxoSearch
     m (ConcreteOutput Credential OutputDatum Value ScriptHash)
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> b) -> UtxoSearch m b
`filterWithAlways` TxOut -> ConcreteOutput Credential OutputDatum Value ScriptHash
TxOut
-> ConcreteOutput
     (OwnerType TxOut)
     (DatumType TxOut)
     (ValueType TxOut)
     (ReferenceScriptType TxOut)
forall out.
IsAbstractOutput out =>
out
-> ConcreteOutput
     (OwnerType out)
     (DatumType out)
     (ValueType out)
     (ReferenceScriptType out)
fromAbstractOutput
    UtxoSearch
  m (ConcreteOutput Credential OutputDatum Value ScriptHash)
-> (ConcreteOutput Credential OutputDatum Value ScriptHash
    -> Maybe (ConcreteOutput Credential () Value ScriptHash))
-> UtxoSearch m (ConcreteOutput Credential () Value ScriptHash)
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
`filterWithPure` ConcreteOutput Credential OutputDatum Value ScriptHash
-> Maybe (ConcreteOutput Credential () Value ScriptHash)
ConcreteOutput Credential OutputDatum Value ScriptHash
-> Maybe
     (ConcreteOutput
        (OwnerType
           (ConcreteOutput Credential OutputDatum Value ScriptHash))
        ()
        (ValueType
           (ConcreteOutput Credential OutputDatum Value ScriptHash))
        (ReferenceScriptType
           (ConcreteOutput Credential OutputDatum Value ScriptHash)))
forall out.
IsTxInfoOutput out =>
out
-> Maybe
     (ConcreteOutput
        (OwnerType out) () (ValueType out) (ReferenceScriptType out))
isOutputWithoutDatum
    UtxoSearch m (ConcreteOutput Credential () Value ScriptHash)
-> (ConcreteOutput Credential () Value ScriptHash
    -> Maybe (ConcreteOutput Credential () Value ScriptHash))
-> UtxoSearch m (ConcreteOutput Credential () Value ScriptHash)
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
`filterWithPure` ConcreteOutput Credential () Value ScriptHash
-> Maybe (ConcreteOutput Credential () Value ScriptHash)
ConcreteOutput Credential () Value ScriptHash
-> Maybe
     (ConcreteOutput
        (OwnerType (ConcreteOutput Credential () Value ScriptHash))
        (DatumType (ConcreteOutput Credential () Value ScriptHash))
        (ValueType (ConcreteOutput Credential () Value ScriptHash))
        (ReferenceScriptType
           (ConcreteOutput Credential () Value ScriptHash)))
forall out.
IsTxInfoOutput out =>
out
-> Maybe
     (ConcreteOutput
        (OwnerType out)
        (DatumType out)
        (ValueType out)
        (ReferenceScriptType out))
isEmptyStakingCredentialOutput
    UtxoSearch m (ConcreteOutput Credential () Value ScriptHash)
-> (ConcreteOutput Credential () Value ScriptHash -> Bool)
-> UtxoSearch m (ConcreteOutput Credential () Value ScriptHash)
forall (m :: * -> *) a.
Monad m =>
UtxoSearch m a -> (a -> Bool) -> UtxoSearch m a
`filterWithPred` (Maybe ScriptHash -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe ScriptHash -> Bool)
-> (ConcreteOutput Credential () Value ScriptHash
    -> Maybe ScriptHash)
-> ConcreteOutput Credential () Value ScriptHash
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Optic'
  A_Lens
  NoIx
  (ConcreteOutput Credential () Value ScriptHash)
  (Maybe ScriptHash)
-> ConcreteOutput Credential () Value ScriptHash
-> Maybe ScriptHash
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic'
  A_Lens
  NoIx
  (ConcreteOutput Credential () Value ScriptHash)
  (Maybe ScriptHash)
Lens'
  (ConcreteOutput Credential () Value ScriptHash)
  (Maybe
     (ReferenceScriptType
        (ConcreteOutput Credential () Value ScriptHash)))
forall o.
IsAbstractOutput o =>
Lens' o (Maybe (ReferenceScriptType o))
outputReferenceScriptL)

-- | Same as 'onlyValueOutputsAtSearch', but also ensures the returned outputs
-- do not contain non-ADA assets. These "vanilla" outputs are perfect candidates
-- to be used for balancing transaction and attaching collaterals.
vanillaOutputsAtSearch ::
  (MonadBlockChainBalancing m, Script.ToAddress addr) =>
  addr ->
  UtxoSearch m (ConcreteOutput Api.Credential () Api.Lovelace Api.ScriptHash)
vanillaOutputsAtSearch :: forall (m :: * -> *) addr.
(MonadBlockChainBalancing m, ToAddress addr) =>
addr
-> UtxoSearch m (ConcreteOutput Credential () Lovelace ScriptHash)
vanillaOutputsAtSearch addr
addr =
  addr
-> UtxoSearch m (ConcreteOutput Credential () Value ScriptHash)
forall (m :: * -> *) addr.
(MonadBlockChainBalancing m, ToAddress addr) =>
addr
-> UtxoSearch m (ConcreteOutput Credential () Value ScriptHash)
onlyValueOutputsAtSearch addr
addr
    UtxoSearch m (ConcreteOutput Credential () Value ScriptHash)
-> (ConcreteOutput Credential () Value ScriptHash
    -> Maybe (ConcreteOutput Credential () Lovelace ScriptHash))
-> UtxoSearch m (ConcreteOutput Credential () Lovelace ScriptHash)
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
`filterWithPure` ConcreteOutput Credential () Value ScriptHash
-> Maybe (ConcreteOutput Credential () Lovelace ScriptHash)
ConcreteOutput Credential () Value ScriptHash
-> Maybe
     (ConcreteOutput
        (OwnerType (ConcreteOutput Credential () Value ScriptHash))
        (DatumType (ConcreteOutput Credential () Value ScriptHash))
        Lovelace
        (ReferenceScriptType
           (ConcreteOutput Credential () Value ScriptHash)))
forall out.
IsTxInfoOutput out =>
out
-> Maybe
     (ConcreteOutput
        (OwnerType out) (DatumType out) Lovelace (ReferenceScriptType out))
isOnlyAdaOutput

-- | Searches for all outputs belonging to a given script
scriptOutputsSearch ::
  (MonadBlockChain m, Script.ToScriptHash s) =>
  s ->
  UtxoSearch m (ConcreteOutput s Api.OutputDatum Api.Value Api.ScriptHash)
scriptOutputsSearch :: forall (m :: * -> *) s.
(MonadBlockChain m, ToScriptHash s) =>
s -> UtxoSearch m (ConcreteOutput s OutputDatum Value ScriptHash)
scriptOutputsSearch s
s =
  UtxoSearch m TxOut
forall (m :: * -> *). MonadBlockChain m => UtxoSearch m TxOut
allUtxosSearch
    UtxoSearch m TxOut
-> (TxOut
    -> ConcreteOutput Credential OutputDatum Value ScriptHash)
-> UtxoSearch
     m (ConcreteOutput Credential OutputDatum Value ScriptHash)
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> b) -> UtxoSearch m b
`filterWithAlways` TxOut -> ConcreteOutput Credential OutputDatum Value ScriptHash
TxOut
-> ConcreteOutput
     (OwnerType TxOut)
     (DatumType TxOut)
     (ValueType TxOut)
     (ReferenceScriptType TxOut)
forall out.
IsAbstractOutput out =>
out
-> ConcreteOutput
     (OwnerType out)
     (DatumType out)
     (ValueType out)
     (ReferenceScriptType out)
fromAbstractOutput
    UtxoSearch
  m (ConcreteOutput Credential OutputDatum Value ScriptHash)
-> (ConcreteOutput Credential OutputDatum Value ScriptHash
    -> Maybe (ConcreteOutput s OutputDatum Value ScriptHash))
-> UtxoSearch m (ConcreteOutput s OutputDatum Value ScriptHash)
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
`filterWithPure` s
-> ConcreteOutput Credential OutputDatum Value ScriptHash
-> Maybe
     (ConcreteOutput
        s
        (DatumType
           (ConcreteOutput Credential OutputDatum Value ScriptHash))
        (ValueType
           (ConcreteOutput Credential OutputDatum Value ScriptHash))
        (ReferenceScriptType
           (ConcreteOutput Credential OutputDatum Value ScriptHash)))
forall out s.
(IsTxInfoOutput out, ToScriptHash s) =>
s
-> out
-> Maybe
     (ConcreteOutput
        s (DatumType out) (ValueType out) (ReferenceScriptType out))
isScriptOutputFrom s
s

-- | Searches for all outputs containing a given script as reference script
referenceScriptOutputsSearch ::
  (MonadBlockChain m, Script.ToScriptHash s) =>
  s ->
  UtxoSearch m (ConcreteOutput Api.Credential Api.OutputDatum Api.Value Api.ScriptHash)
referenceScriptOutputsSearch :: forall (m :: * -> *) s.
(MonadBlockChain m, ToScriptHash s) =>
s
-> UtxoSearch
     m (ConcreteOutput Credential OutputDatum Value ScriptHash)
referenceScriptOutputsSearch s
s =
  UtxoSearch m TxOut
forall (m :: * -> *). MonadBlockChain m => UtxoSearch m TxOut
allUtxosSearch
    UtxoSearch m TxOut
-> (TxOut
    -> ConcreteOutput Credential OutputDatum Value ScriptHash)
-> UtxoSearch
     m (ConcreteOutput Credential OutputDatum Value ScriptHash)
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> b) -> UtxoSearch m b
`filterWithAlways` TxOut -> ConcreteOutput Credential OutputDatum Value ScriptHash
TxOut
-> ConcreteOutput
     (OwnerType TxOut)
     (DatumType TxOut)
     (ValueType TxOut)
     (ReferenceScriptType TxOut)
forall out.
IsAbstractOutput out =>
out
-> ConcreteOutput
     (OwnerType out)
     (DatumType out)
     (ValueType out)
     (ReferenceScriptType out)
fromAbstractOutput
    UtxoSearch
  m (ConcreteOutput Credential OutputDatum Value ScriptHash)
-> (ConcreteOutput Credential OutputDatum Value ScriptHash
    -> Maybe (ConcreteOutput Credential OutputDatum Value ScriptHash))
-> UtxoSearch
     m (ConcreteOutput Credential OutputDatum Value ScriptHash)
forall (m :: * -> *) a b.
Monad m =>
UtxoSearch m a -> (a -> Maybe b) -> UtxoSearch m b
`filterWithPure` s
-> ConcreteOutput Credential OutputDatum Value ScriptHash
-> Maybe
     (ConcreteOutput
        (OwnerType
           (ConcreteOutput Credential OutputDatum Value ScriptHash))
        (DatumType
           (ConcreteOutput Credential OutputDatum Value ScriptHash))
        (ValueType
           (ConcreteOutput Credential OutputDatum Value ScriptHash))
        ScriptHash)
forall out s.
(IsTxInfoOutput out, ToScriptHash s) =>
s
-> out
-> Maybe
     (ConcreteOutput
        (OwnerType out) (DatumType out) (ValueType out) ScriptHash)
isReferenceScriptOutputFrom s
s