11module BotPlutusInterface.Collateral (
22 getInMemCollateral ,
33 setInMemCollateral ,
4- filterCollateral ,
54 mkCollateralTx ,
6- removeCollateralFromPage ,
7- removeCollateralFromMap ,
5+ withCollateralHandling ,
86) where
97
108import BotPlutusInterface.Types (
@@ -16,12 +14,32 @@ import BotPlutusInterface.Types (
1614 )
1715import Cardano.Prelude (Void )
1816import Control.Concurrent.STM (atomically , readTVarIO , writeTVar )
17+ import Control.Monad (unless )
1918import Data.Kind (Type )
20- import Data.Map (Map )
21- import Data.Map qualified as Map
22- import Ledger (ChainIndexTxOut , PaymentPubKeyHash (PaymentPubKeyHash ), TxOutRef )
19+ import Ledger (PaymentPubKeyHash (PaymentPubKeyHash ), TxOutRef )
2320import Ledger.Constraints qualified as Constraints
2421import Plutus.ChainIndex (Page (pageItems ))
22+ import Plutus.ChainIndex.Api (
23+ IsUtxoResponse (IsUtxoResponse ),
24+ QueryResponse (QueryResponse ),
25+ TxosResponse (paget ),
26+ UtxosResponse (page ),
27+ )
28+ import Plutus.Contract.Effects (
29+ ChainIndexQuery (.. ),
30+ ChainIndexResponse (
31+ TxOutRefResponse ,
32+ TxoSetAtResponse ,
33+ UnspentTxOutResponse ,
34+ UnspentTxOutsAtResponse ,
35+ UtxoSetAtResponse ,
36+ UtxoSetMembershipResponse ,
37+ UtxoSetWithCurrencyResponse
38+ ),
39+ PABReq (ChainIndexQueryReq ),
40+ PABResp (ChainIndexQueryResp ),
41+ matches ,
42+ )
2543import Prelude
2644
2745getInMemCollateral :: forall (w :: Type ). ContractEnvironment w -> IO (Maybe CollateralUtxo )
@@ -38,16 +56,68 @@ mkCollateralTx pabConf = Constraints.mkTx @Void mempty txc
3856 txc :: Constraints. TxConstraints Void Void
3957 txc = Constraints. mustPayToPubKey (PaymentPubKeyHash $ pcOwnPubKeyHash pabConf) (collateralValue pabConf)
4058
41- filterCollateral :: CollateralUtxo -> [TxOutRef ] -> [TxOutRef ]
42- filterCollateral (CollateralUtxo collateralTxOutRef) = filter (/= collateralTxOutRef)
59+ -- | Middleware to run `chain-index` queries and filter out collateral output from response.
60+ withCollateralHandling ::
61+ Monad m =>
62+ Maybe CollateralUtxo ->
63+ (ChainIndexQuery -> m ChainIndexResponse ) ->
64+ ChainIndexQuery ->
65+ m ChainIndexResponse
66+ withCollateralHandling mCollateral runChainIndexQuery = \ query -> do
67+ response <-
68+ adjustChainIndexResponse mCollateral query
69+ <$> runChainIndexQuery query
70+ ensureMatches query response
71+ pure response
72+ where
73+ ensureMatches query result =
74+ unless (matches (ChainIndexQueryReq query) (ChainIndexQueryResp result)) $
75+ error $
76+ mconcat
77+ [ " Chain-index request doesn't match response."
78+ , " \n Request: " ++ show query
79+ , " \n Response:" ++ show result
80+ ]
81+
82+ adjustChainIndexResponse :: Maybe CollateralUtxo -> ChainIndexQuery -> ChainIndexResponse -> ChainIndexResponse
83+ adjustChainIndexResponse mc ciQuery ciResponse =
84+ case mc of
85+ Nothing -> ciResponse
86+ Just (CollateralUtxo collateralOref) -> case (ciQuery, ciResponse) of
87+ -- adjustment based on response
88+ (_, UtxoSetAtResponse utxosResp) ->
89+ let newPage = removeCollateralFromPage mc (page utxosResp)
90+ in UtxoSetAtResponse $ utxosResp {page = newPage}
91+ (_, TxoSetAtResponse txosResp) ->
92+ let newPaget = removeCollateralFromPage mc (paget txosResp)
93+ in TxoSetAtResponse $ txosResp {paget = newPaget}
94+ (_, UnspentTxOutsAtResponse (QueryResponse refsAndOuts nq)) ->
95+ let filtered = filter (\ v -> fst v /= collateralOref) refsAndOuts
96+ in UnspentTxOutsAtResponse $ QueryResponse filtered nq
97+ (_, UtxoSetWithCurrencyResponse utxosResp) ->
98+ let newPage = removeCollateralFromPage mc (page utxosResp)
99+ in UtxoSetWithCurrencyResponse $ utxosResp {page = newPage}
100+ -- adjustment based on request
101+ (UtxoSetMembership oref, UtxoSetMembershipResponse (IsUtxoResponse ct isU)) ->
102+ UtxoSetMembershipResponse $
103+ IsUtxoResponse ct $
104+ oref /= collateralOref && isU
105+ (TxOutFromRef oref, TxOutRefResponse _) ->
106+ if collateralOref == oref
107+ then TxOutRefResponse Nothing
108+ else ciResponse
109+ (UnspentTxOutFromRef oref, UnspentTxOutResponse _) ->
110+ if collateralOref == oref
111+ then UnspentTxOutResponse Nothing
112+ else ciResponse
113+ -- all other cases
114+ (_, rest) -> rest
43115
44116-- | Removes collateral utxo from the UtxoResponse page. Receives `Nothing` if Collateral uninitialized.
45117removeCollateralFromPage :: Maybe CollateralUtxo -> Page TxOutRef -> Page TxOutRef
46118removeCollateralFromPage = \ case
47119 Nothing -> id
48- Just txOutRef -> \ page -> page {pageItems = filterCollateral txOutRef (pageItems page)}
120+ Just txOutRef -> \ page' -> page' {pageItems = filterCollateral txOutRef (pageItems page' )}
49121
50- removeCollateralFromMap :: Maybe CollateralUtxo -> Map TxOutRef ChainIndexTxOut -> Map TxOutRef ChainIndexTxOut
51- removeCollateralFromMap = \ case
52- Nothing -> id
53- Just (CollateralUtxo collateral) -> Map. filterWithKey (\ oref _ -> collateral /= oref)
122+ filterCollateral :: CollateralUtxo -> [TxOutRef ] -> [TxOutRef ]
123+ filterCollateral (CollateralUtxo collateralTxOutRef) = filter (/= collateralTxOutRef)
0 commit comments