1
1
module BotPlutusInterface.Collateral (
2
2
getInMemCollateral ,
3
3
setInMemCollateral ,
4
- filterCollateral ,
5
4
mkCollateralTx ,
6
- removeCollateralFromPage ,
7
- removeCollateralFromMap ,
5
+ withCollateralHandling ,
8
6
) where
9
7
10
8
import BotPlutusInterface.Types (
@@ -16,12 +14,32 @@ import BotPlutusInterface.Types (
16
14
)
17
15
import Cardano.Prelude (Void )
18
16
import Control.Concurrent.STM (atomically , readTVarIO , writeTVar )
17
+ import Control.Monad (unless )
19
18
import 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 )
23
20
import Ledger.Constraints qualified as Constraints
24
21
import 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
+ )
25
43
import Prelude
26
44
27
45
getInMemCollateral :: forall (w :: Type ). ContractEnvironment w -> IO (Maybe CollateralUtxo )
@@ -38,16 +56,68 @@ mkCollateralTx pabConf = Constraints.mkTx @Void mempty txc
38
56
txc :: Constraints. TxConstraints Void Void
39
57
txc = Constraints. mustPayToPubKey (PaymentPubKeyHash $ pcOwnPubKeyHash pabConf) (collateralValue pabConf)
40
58
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
43
115
44
116
-- | Removes collateral utxo from the UtxoResponse page. Receives `Nothing` if Collateral uninitialized.
45
117
removeCollateralFromPage :: Maybe CollateralUtxo -> Page TxOutRef -> Page TxOutRef
46
118
removeCollateralFromPage = \ case
47
119
Nothing -> id
48
- Just txOutRef -> \ page -> page {pageItems = filterCollateral txOutRef (pageItems page)}
120
+ Just txOutRef -> \ page' -> page' {pageItems = filterCollateral txOutRef (pageItems page' )}
49
121
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