@@ -8,35 +8,27 @@ module Coop.Plutus (
88 certV ,
99 mkCertMp ,
1010 pmustSpendAtLeastAa ,
11+ exampleConsumer ,
1112) where
1213
1314import Coop.Plutus.Aux (pcurrencyTokenQuantity , pcurrencyValue , pdatumFromTxOut , pdjust , pdnothing , pfindMap , pfoldTxInputs , pfoldTxOutputs , pfoldTxRefs , phasCurrency , pmaybeData , pmustBeSignedBy , pmustBurnOwnSingletonValue , pmustMintCurrency , pmustPayCurrencyWithDatumTo , pmustSpendAtLeast , pmustValidateAfter , pownCurrencySymbol , ptryFromData , punit )
1415import Coop.Plutus.Types (PAuthMpParams , PAuthMpRedeemer (PAuthMpBurn , PAuthMpMint ), PAuthParams , PCertDatum , PCertMpParams , PCertMpRedeemer (PCertMpBurn , PCertMpMint ), PFsDatum , PFsMpParams , PFsMpRedeemer (PFsMpBurn , PFsMpMint ))
1516import Plutarch (POpaque , pmatch , popaque )
17+ import Plutarch.Api.V1.AssocMap (plookup )
1618import Plutarch.Api.V1.Value (passertPositive , pnormalize , pvalueOf )
1719import Plutarch.Api.V1.Value qualified as PValue
18- import Plutarch.Api.V2 (
19- AmountGuarantees (NonZero , Positive ),
20- KeyGuarantees (Sorted ),
21- PCurrencySymbol ,
22- PMaybeData ,
23- PMintingPolicy ,
24- PTokenName (PTokenName ),
25- PTuple ,
26- PTxInInfo ,
27- PTxOut ,
28- PValidator ,
29- PValue ,
30- )
20+ import Plutarch.Api.V2 (AmountGuarantees (NonZero , Positive ), KeyGuarantees (Sorted , Unsorted ), PCurrencySymbol , PMap , PMaybeData , PMintingPolicy , PTokenName (PTokenName ), PTuple , PTxInInfo , PTxOut , PValidator , PValue )
3121import Plutarch.Api.V2.Contexts (PScriptContext )
32- import Plutarch.Bool (pif )
22+ import Plutarch.Bool (PBool , pif )
23+ import Plutarch.Builtin (PBuiltinPair , pasConstr , pfstBuiltin , psndBuiltin )
3324import Plutarch.Crypto (pblake2b_256 )
3425import Plutarch.Extra.Interval (pcontains )
26+ import Plutarch.List (pmap )
3527import Plutarch.Monadic qualified as P
3628import Plutarch.Num (PNum (pnegate , (#+) ))
37- import Plutarch.Prelude (ClosedTerm , PAsData , PBuiltinList , PByteString , PEq ((#==) ), PInteger , PListLike (pcons , pnil ), PPair (PPair ), PPartialOrd ((#<) , (#<=) ), Term , pcon , pconsBS , pfield , pfoldl , pfromData , phoistAcyclic , plam , plet , pletFields , ptrace , ptraceError , (#) , (#$) , type (:--> ))
29+ import Plutarch.Prelude (ClosedTerm , PAsData , PBuiltinList , PByteString , PData , PEq ((#==) ), PInteger , PListLike (pcons , phead , pnil ), PMaybe ( PJust ), PPair (PPair ), PPartialOrd ((#<) , (#<=) ), Term , pcon , pconsBS , pconstant , pfield , pfoldl , pfromData , phoistAcyclic , plam , plet , pletFields , ptrace , ptraceError , (#) , (#$) , type (:--> ))
3830import PlutusTx.Prelude (Group (inv ))
39- import Prelude (Monoid (mempty ), Semigroup ((<>) ), ($) )
31+ import Prelude (Monoid (mempty ), Semigroup ((<>) ), ($) , (.) )
4032
4133{- | Validates spending from @FsV
4234
@@ -598,3 +590,93 @@ pmustSpendAtLeastAa = phoistAcyclic $
598590 (atLeastAaQ #<= aaTokensSpent)
599591 (ptrace " pmustSpendAtLeastAa: Spent at least the specified amount of AA tokens" $ pblake2b_256 # tnBytes)
600592 (ptraceError " pmustSpendAtLeastAa: Must spend at least the specified amount of AA tokens" )
593+
594+ {- | Example Consumer validator that authenticates and processes a referenced
595+ FactStatement UTxO
596+
597+ - check that the reference input holds the appropriate $FS token (with the
598+ trusted COOP Oracle's CurrencySymbol),
599+ - parse the Fact Statement embedded in the UTxO datum and perform assertions.
600+
601+ To demonstrate the COOP provided Plutus JSON encoding a file was created with the COOP
602+ provided `plutus-json-cli` tool:
603+
604+ \$ plutus-json-cli from-json -i resources/sample.json -o resources/sample.pd.cbor
605+
606+ This served as an exemplary Fact Statement.
607+ -}
608+ exampleConsumer :: ClosedTerm (PCurrencySymbol :--> PValidator )
609+ exampleConsumer = phoistAcyclic $
610+ plam $ \ trustedCs _ _ ctx -> ptrace " exampleConsumer" P. do
611+ ctx' <- pletFields @ '[" txInfo" ] ctx
612+ txInfo <- pletFields @ '[" referenceInputs" ] ctx'. txInfo
613+
614+ ptrace " exampleConsumer: Looking for a Fact Statement reference input from a trusted COOP Oracle"
615+ refInput <- pletFields @ '[" resolved" ] $ phead # pfromData txInfo. referenceInputs
616+ refInVal <- plet $ pfield @ " value" # refInput. resolved
617+
618+ ptrace " exampleConsumer: Looking for a Fact Statement reference input from a trusted COOP Oracle"
619+ pif
620+ (phasCurrency # trustedCs # refInVal)
621+ ( ptrace
622+ " exampleConsumer: Found an authentic Fact Statement reference input from a trusted COOP Oracle"
623+ P. do
624+ -- Parse the FsDatum available in the referenced input
625+ fsDatum <- pletFields @ '[" fd'fs" , " fd'submitter" , " fd'gcAfter" , " fd'fsId" ] $ pdatumFromTxOut @ PFsDatum # ctx # refInput. resolved
626+
627+ -- Take the Fact Statement payload in `fd'fs` field and try to parse it as a PlutusData Map
628+ factStatement :: Term s (PMap 'Unsorted PByteString PData ) <- plet $ pfromData $ ptryFromData fsDatum. fd'fs
629+
630+ -- Take the "array" field in the Fact Statement and assert that it is [1,2,3]
631+ PJust arrayNumbers''' <- pmatch $ plookup # pconstant " array" # factStatement
632+ -- Parse it as Plutus List
633+ arrayNumbers' :: Term s (PBuiltinList (PAsData PInteger )) <- plet $ pfromData $ ptryFromData arrayNumbers'''
634+ -- Parse the elements within as Plutus Integer
635+ arrayNumbers <- plet $ pmap # plam pfromData # arrayNumbers'
636+ _ <- plet $ pif (arrayNumbers #== pconstant [1 , 2 , 3 ]) (popaque punit) (ptraceError " Expected Plutus List [1,2,3]" )
637+
638+ -- Take the "boolean" field in the Fact Statement and assert that it is true
639+ PJust boolean' <- pmatch $ plookup # pconstant " boolean" # factStatement
640+ boolean :: Term s PBool <- plet $ pfromData $ ptryFromData boolean'
641+ _ <- plet $ pif boolean (popaque punit) (ptraceError " Expected a Plutus Boolean true" )
642+
643+ -- Take the "null" field in the Fact Statement and assert that it is null
644+ PJust null' <- pmatch $ plookup # pconstant " null" # factStatement
645+ null :: Term s (PBuiltinPair PInteger (PBuiltinList PData )) <- plet $ pasConstr # null'
646+ _ <- plet $ pif ((pfstBuiltin # null ) #== 2 ) (popaque punit) (ptraceError " Expected a Plutus Constr 2 []" )
647+ _ <- plet $ pif ((psndBuiltin # null ) #== pconstant [] ) (popaque punit) (ptraceError " Expected a Plutus Constr 2 []" )
648+
649+ -- Take the "integer" field in the Fact Statement and assert that it is 123
650+ PJust integer' <- pmatch $ plookup # pconstant " integer" # factStatement
651+ integer :: Term s PInteger <- plet $ pfromData $ ptryFromData integer'
652+ _ <- plet $ pif (integer #== pconstant 123 ) (popaque punit) (ptraceError " Expected a Plutus Integer 123" )
653+
654+ -- Take the "big_integer" field in the Fact Statement and assert that it is 12300000000000000000000000
655+ PJust bigInteger' <- pmatch $ plookup # pconstant " big_integer" # factStatement
656+ bigInteger'' :: Term s (PBuiltinPair PInteger (PBuiltinList PData )) <- plet $ pasConstr # bigInteger'
657+ bigInteger''' :: Term s (PBuiltinList PInteger ) <- plet $ pmap # plam (pfromData . ptryFromData) # (psndBuiltin # bigInteger'')
658+ _ <- plet $ pif ((pfstBuiltin # bigInteger'') #== 3 ) (popaque punit) (ptraceError " Expected a Plutus Constr 3 [12300000000000000000000000, 0]" )
659+ _ <- plet $ pif (bigInteger''' #== pconstant [12300000000000000000000000 , 0 ]) (popaque punit) (ptraceError " Expected a Plutus Constr 3 [12300000000000000000000000, 0]" )
660+
661+ -- Take the "real" field in the Fact Statement and assert that it is 123.123
662+ PJust real' <- pmatch $ plookup # pconstant " real" # factStatement
663+ real'' :: Term s (PBuiltinPair PInteger (PBuiltinList PData )) <- plet $ pasConstr # real'
664+ real''' :: Term s (PBuiltinList PInteger ) <- plet $ pmap # plam (pfromData . ptryFromData) # (psndBuiltin # real'')
665+ _ <- plet $ pif ((pfstBuiltin # real'') #== 3 ) (popaque punit) (ptraceError " Expected a Plutus Constr 3 [123123, -3]" )
666+ _ <- plet $ pif (real''' #== pconstant [123123 , - 3 ]) (popaque punit) (ptraceError " Expected a Plutus Constr 3 [123123, -3]" )
667+
668+ -- Take the "big_real" field in the Fact Statement and assert that it is 12300000000000000000000000.123
669+ PJust big_real' <- pmatch $ plookup # pconstant " big_real" # factStatement
670+ big_real'' :: Term s (PBuiltinPair PInteger (PBuiltinList PData )) <- plet $ pasConstr # big_real'
671+ big_real''' :: Term s (PBuiltinList PInteger ) <- plet $ pmap # plam (pfromData . ptryFromData) # (psndBuiltin # big_real'')
672+ _ <- plet $ pif ((pfstBuiltin # big_real'') #== 3 ) (popaque punit) (ptraceError " Expected a Plutus Constr 3 [12300000000000000000000000123, -3]" )
673+ _ <- plet $ pif (big_real''' #== pconstant [12300000000000000000000000123 , - 3 ]) (popaque punit) (ptraceError " Expected a Plutus Constr 3 [12300000000000000000000000123, -3]" )
674+
675+ -- Take the "string" field in the Fact Statement and assert that it is "Hello World"
676+ PJust string' <- pmatch $ plookup # pconstant " string" # factStatement
677+ string'' :: Term s PByteString <- plet $ pfromData $ ptryFromData string'
678+ _ <- plet $ pif (string'' #== pconstant " Hello World" ) (popaque punit) (ptraceError " Expected a Plutus Bytestring \" Hello World\" " )
679+
680+ ptrace " exampleConsumer: Everything worked!" $ popaque punit
681+ )
682+ (ptraceError " exampleConsumer: Must have a Fact Statement reference input from a trusted COOP Oracle" )
0 commit comments