From c6aa6ac5d5a9df8b1c92975652f55acba24c200c Mon Sep 17 00:00:00 2001 From: Seungheon Oh Date: Thu, 14 Apr 2022 11:38:06 -0400 Subject: [PATCH 1/5] New utility functions added `pisScriptAddress`, `pfindEffectInput`, and `pfindEffectAddress`. These functions are commonly used by effects. --- agora/Agora/Utils.hs | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index 83ac342..4519236 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -32,6 +32,9 @@ module Agora.Utils ( allOutputs, anyInput, allInputs, + pisScriptAddress, + pfindEffectInput, + pfindEffectAddress, ) where -------------------------------------------------------------------------------- @@ -42,10 +45,11 @@ import Plutus.V1.Ledger.Value (AssetClass (..)) import Plutarch.Api.V1 ( PAddress, + PCredential (PScriptCredential), PCurrencySymbol, PDatum, PDatumHash, - PMaybeData (PDJust), + PMaybeData (PDJust, PDNothing), PPubKeyHash, PTokenName, PTuple, @@ -390,3 +394,32 @@ psingletonValue = phoistAcyclic $ outerTup = pcon $ PMap $ psingleton #$ ppairDataBuiltin # pdata sym # pdata innerTup res = pcon $ PValue outerTup in res + +-- | Determine if an address is a script address +pisScriptAddress :: Term s (PAddress :--> PBool) +pisScriptAddress = phoistAcyclic $ + plam $ \addr' -> P.do + address <- pletFields @'["credential", "stakingCredential"] addr' + scred <- pmatch $ pfromData address.stakingCredential + case scred of + PDNothing _ -> P.do + cred <- pmatch $ pfromData address.credential + case cred of + PScriptCredential _ -> pconstant True + _ -> pconstant False + _ -> pconstant False + +-- | Finds the TxInInfo of an effect from TxInfo and TxOutRef +pfindEffectInput :: Term s (PTxInfo :--> PTxOutRef :--> PTxInInfo) +pfindEffectInput = phoistAcyclic $ + plam $ \txInfo spending' -> P.do + input <- plet $ pfromData $ pfield @"inputs" # txInfo + spending <- plet $ pdata spending' + PJust result <- pmatch $ pfind # plam (\x -> pfield @"outRef" # x #== spending) # input + pfromData result + +-- | Finds the address of an effect from TxInfo and TxOutRef +pfindEffectAddress :: Term s (PTxInfo :--> PTxOutRef :--> PTxOut) +pfindEffectAddress = phoistAcyclic $ + plam $ \txInfo spending -> P.do + pfromData $ pfield @"resolved" #$ pfindEffectInput # txInfo # spending From 22d66e8a9decc0cf882e32d09e2ef9abd24eefe2 Mon Sep 17 00:00:00 2001 From: Seungheon Oh Date: Thu, 14 Apr 2022 17:19:18 -0500 Subject: [PATCH 2/5] More utility functions functions that I missed from Conner's governor branch... --- agora/Agora/Utils.hs | 67 +++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index 4519236..ba22d51 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -26,15 +26,18 @@ module Agora.Utils ( psingletonValue, pfindMap, pnotNull, + pisJust, -- * Functions which should (probably) not be upstreamed anyOutput, allOutputs, anyInput, allInputs, - pisScriptAddress, pfindEffectInput, pfindEffectAddress, + pscriptHashFromAddress, + pfindOutputsToAddress, + pfindTxOutDatum, ) where -------------------------------------------------------------------------------- @@ -49,7 +52,8 @@ import Plutarch.Api.V1 ( PCurrencySymbol, PDatum, PDatumHash, - PMaybeData (PDJust, PDNothing), + PMap, + PMaybeData (PDJust), PPubKeyHash, PTokenName, PTuple, @@ -57,11 +61,14 @@ import Plutarch.Api.V1 ( PTxInfo (PTxInfo), PTxOut (PTxOut), PTxOutRef, + PValidatorHash, + PValue, ) import Plutarch.Api.V1.AssocMap (PMap (PMap)) import Plutarch.Api.V1.Value (PValue (PValue)) import Plutarch.Builtin (ppairDataBuiltin) import Plutarch.Internal (punsafeCoerce) +import Plutarch.List (pconvertLists) import Plutarch.Monadic qualified as P -------------------------------------------------------------------------------- @@ -147,6 +154,15 @@ pfromMaybe = phoistAcyclic $ PJust a' -> a' PNothing -> e +-- | Yield True is a given PMaybe is of form PJust _ +pisJust :: forall a s. Term s (PMaybe a :--> PBool) +pisJust = phoistAcyclic $ + plam $ \v' -> P.do + v <- pmatch v' + case v of + PJust _ -> pconstant True + PNothing -> pconstant False + -- | Escape with a particular value on expecting 'Just'. For use in monadic context. pexpectJust :: forall r a s. @@ -395,20 +411,6 @@ psingletonValue = phoistAcyclic $ res = pcon $ PValue outerTup in res --- | Determine if an address is a script address -pisScriptAddress :: Term s (PAddress :--> PBool) -pisScriptAddress = phoistAcyclic $ - plam $ \addr' -> P.do - address <- pletFields @'["credential", "stakingCredential"] addr' - scred <- pmatch $ pfromData address.stakingCredential - case scred of - PDNothing _ -> P.do - cred <- pmatch $ pfromData address.credential - case cred of - PScriptCredential _ -> pconstant True - _ -> pconstant False - _ -> pconstant False - -- | Finds the TxInInfo of an effect from TxInfo and TxOutRef pfindEffectInput :: Term s (PTxInfo :--> PTxOutRef :--> PTxInInfo) pfindEffectInput = phoistAcyclic $ @@ -423,3 +425,36 @@ pfindEffectAddress :: Term s (PTxInfo :--> PTxOutRef :--> PTxOut) pfindEffectAddress = phoistAcyclic $ plam $ \txInfo spending -> P.do pfromData $ pfield @"resolved" #$ pfindEffectInput # txInfo # spending + +-- | Get script hash from an Address. +pscriptHashFromAddress :: Term s (PAddress :--> PMaybe PValidatorHash) +pscriptHashFromAddress = phoistAcyclic $ + plam $ \addr -> P.do + cred <- pmatch $ pfromData $ pfield @"credential" # addr + case cred of + PScriptCredential h -> pcon $ PJust $ pfield @"_0" # h + _ -> pcon PNothing + +-- | Find all TxOuts sent to an Address +pfindOutputsToAddress :: Term s (PTxInfo :--> PAddress :--> PList PTxOut) +pfindOutputsToAddress = phoistAcyclic $ + plam $ \info address' -> P.do + address <- plet $ pdata address' + let outputs = pfromData $ pfield @"outputs" # info + filteredOutputs = + pfilter + # ( plam $ \(pfromData -> txOut) -> P.do + selfAddress <- plet $ pfield @"address" # txOut + selfAddress #== address + ) + # outputs + pmap @PList # plam pfromData #$ pconvertLists # filteredOutputs + +-- | Find datum in a TxOut +pfindTxOutDatum :: Term s (PTxInfo :--> PTxOut :--> PMaybe PDatum) +pfindTxOutDatum = phoistAcyclic $ + plam $ \info out -> P.do + datumHash' <- pmatch $ pfromData $ pfield @"datumHash" # out + case datumHash' of + PDJust ((pfield @"_0" #) -> datumHash) -> pfindDatum # datumHash # info + _ -> pcon PNothing From f3f7f131febf2f975696bd4061d1f0e69efeb078 Mon Sep 17 00:00:00 2001 From: Seungheon Oh Date: Thu, 14 Apr 2022 23:23:50 -0500 Subject: [PATCH 3/5] Connor's suggestions --- agora/Agora/Utils.hs | 46 ++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index ba22d51..118bd0a 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -33,11 +33,10 @@ module Agora.Utils ( allOutputs, anyInput, allInputs, - pfindEffectInput, - pfindEffectAddress, - pscriptHashFromAddress, - pfindOutputsToAddress, - pfindTxOutDatum, + findTxOutByTxOutRef, + scriptHashFromAddress, + findOutputsToAddress, + findTxOutDatum, ) where -------------------------------------------------------------------------------- @@ -154,7 +153,7 @@ pfromMaybe = phoistAcyclic $ PJust a' -> a' PNothing -> e --- | Yield True is a given PMaybe is of form PJust _ +-- | Yield True if a given PMaybe is of form PJust _ pisJust :: forall a s. Term s (PMaybe a :--> PBool) pisJust = phoistAcyclic $ plam $ \v' -> P.do @@ -411,24 +410,17 @@ psingletonValue = phoistAcyclic $ res = pcon $ PValue outerTup in res --- | Finds the TxInInfo of an effect from TxInfo and TxOutRef -pfindEffectInput :: Term s (PTxInfo :--> PTxOutRef :--> PTxInInfo) -pfindEffectInput = phoistAcyclic $ - plam $ \txInfo spending' -> P.do - input <- plet $ pfromData $ pfield @"inputs" # txInfo - spending <- plet $ pdata spending' - PJust result <- pmatch $ pfind # plam (\x -> pfield @"outRef" # x #== spending) # input - pfromData result - --- | Finds the address of an effect from TxInfo and TxOutRef -pfindEffectAddress :: Term s (PTxInfo :--> PTxOutRef :--> PTxOut) -pfindEffectAddress = phoistAcyclic $ - plam $ \txInfo spending -> P.do - pfromData $ pfield @"resolved" #$ pfindEffectInput # txInfo # spending +-- | Finds the TxOut of an effect from TxInfo and TxOutRef +findTxOutByTxOutRef :: Term s (PTxOutRef :--> PTxInfo :--> PMaybe PTxOut) +findTxOutByTxOutRef = phoistAcyclic $ + plam $ \txOutRef txInfo -> + pmatch (pfindTxInByTxOutRef # txOutRef # txInfo) $ \case + PJust ((pfield @"resolved" #) -> txOut) -> pcon $ PJust txOut + PNothing -> pcon PNothing -- | Get script hash from an Address. -pscriptHashFromAddress :: Term s (PAddress :--> PMaybe PValidatorHash) -pscriptHashFromAddress = phoistAcyclic $ +scriptHashFromAddress :: Term s (PAddress :--> PMaybe PValidatorHash) +scriptHashFromAddress = phoistAcyclic $ plam $ \addr -> P.do cred <- pmatch $ pfromData $ pfield @"credential" # addr case cred of @@ -436,8 +428,8 @@ pscriptHashFromAddress = phoistAcyclic $ _ -> pcon PNothing -- | Find all TxOuts sent to an Address -pfindOutputsToAddress :: Term s (PTxInfo :--> PAddress :--> PList PTxOut) -pfindOutputsToAddress = phoistAcyclic $ +findOutputsToAddress :: Term s (PTxInfo :--> PAddress :--> PList PTxOut) +findOutputsToAddress = phoistAcyclic $ plam $ \info address' -> P.do address <- plet $ pdata address' let outputs = pfromData $ pfield @"outputs" # info @@ -450,9 +442,9 @@ pfindOutputsToAddress = phoistAcyclic $ # outputs pmap @PList # plam pfromData #$ pconvertLists # filteredOutputs --- | Find datum in a TxOut -pfindTxOutDatum :: Term s (PTxInfo :--> PTxOut :--> PMaybe PDatum) -pfindTxOutDatum = phoistAcyclic $ +-- | Find the data corresponding to a TxOut, if there is one +findTxOutDatum :: Term s (PTxInfo :--> PTxOut :--> PMaybe PDatum) +findTxOutDatum = phoistAcyclic $ plam $ \info out -> P.do datumHash' <- pmatch $ pfromData $ pfield @"datumHash" # out case datumHash' of From b4a6cb917955380b6948124d3cd0cd3673563f2a Mon Sep 17 00:00:00 2001 From: Seungheon Oh Date: Fri, 15 Apr 2022 08:52:42 -0500 Subject: [PATCH 4/5] Emily's suggestions & fixed building --- agora/Agora/Utils.hs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index 118bd0a..2e6efff 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -153,7 +153,7 @@ pfromMaybe = phoistAcyclic $ PJust a' -> a' PNothing -> e --- | Yield True if a given PMaybe is of form PJust _ +-- | Yield True if a given PMaybe is of form PJust _. pisJust :: forall a s. Term s (PMaybe a :--> PBool) pisJust = phoistAcyclic $ plam $ \v' -> P.do @@ -421,26 +421,26 @@ findTxOutByTxOutRef = phoistAcyclic $ -- | Get script hash from an Address. scriptHashFromAddress :: Term s (PAddress :--> PMaybe PValidatorHash) scriptHashFromAddress = phoistAcyclic $ - plam $ \addr -> P.do - cred <- pmatch $ pfromData $ pfield @"credential" # addr - case cred of + plam $ \addr -> + pmatch (pfromData $ pfield @"credential" # addr) $ \case PScriptCredential h -> pcon $ PJust $ pfield @"_0" # h _ -> pcon PNothing -- | Find all TxOuts sent to an Address -findOutputsToAddress :: Term s (PTxInfo :--> PAddress :--> PList PTxOut) +findOutputsToAddress :: Term s (PTxInfo :--> PAddress :--> PBuiltinList PTxOut) findOutputsToAddress = phoistAcyclic $ plam $ \info address' -> P.do address <- plet $ pdata address' let outputs = pfromData $ pfield @"outputs" # info filteredOutputs = pfilter - # ( plam $ \(pfromData -> txOut) -> P.do + # plam + ( \(pfromData -> txOut) -> P.do selfAddress <- plet $ pfield @"address" # txOut selfAddress #== address ) # outputs - pmap @PList # plam pfromData #$ pconvertLists # filteredOutputs + pmap # plam pfromData #$ pconvertLists # filteredOutputs -- | Find the data corresponding to a TxOut, if there is one findTxOutDatum :: Term s (PTxInfo :--> PTxOut :--> PMaybe PDatum) From b67a886cd243ab794402dc27d6f04a767b0bc74f Mon Sep 17 00:00:00 2001 From: Seungheon Oh Date: Fri, 15 Apr 2022 09:02:16 -0500 Subject: [PATCH 5/5] fixes --- agora/Agora/Utils.hs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index 2e6efff..e05e4ee 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -67,7 +67,6 @@ import Plutarch.Api.V1.AssocMap (PMap (PMap)) import Plutarch.Api.V1.Value (PValue (PValue)) import Plutarch.Builtin (ppairDataBuiltin) import Plutarch.Internal (punsafeCoerce) -import Plutarch.List (pconvertLists) import Plutarch.Monadic qualified as P -------------------------------------------------------------------------------- @@ -423,11 +422,11 @@ scriptHashFromAddress :: Term s (PAddress :--> PMaybe PValidatorHash) scriptHashFromAddress = phoistAcyclic $ plam $ \addr -> pmatch (pfromData $ pfield @"credential" # addr) $ \case - PScriptCredential h -> pcon $ PJust $ pfield @"_0" # h + PScriptCredential ((pfield @"_0" #) -> h) -> pcon $ PJust h _ -> pcon PNothing -- | Find all TxOuts sent to an Address -findOutputsToAddress :: Term s (PTxInfo :--> PAddress :--> PBuiltinList PTxOut) +findOutputsToAddress :: Term s (PTxInfo :--> PAddress :--> PBuiltinList (PAsData PTxOut)) findOutputsToAddress = phoistAcyclic $ plam $ \info address' -> P.do address <- plet $ pdata address' @@ -435,12 +434,9 @@ findOutputsToAddress = phoistAcyclic $ filteredOutputs = pfilter # plam - ( \(pfromData -> txOut) -> P.do - selfAddress <- plet $ pfield @"address" # txOut - selfAddress #== address - ) + (\(pfromData -> txOut) -> pfield @"address" # txOut #== address) # outputs - pmap # plam pfromData #$ pconvertLists # filteredOutputs + filteredOutputs -- | Find the data corresponding to a TxOut, if there is one findTxOutDatum :: Term s (PTxInfo :--> PTxOut :--> PMaybe PDatum)