ensure that script outputs won't be locked

This commit is contained in:
Hongrui Fang 2023-03-29 21:36:45 +08:00
parent 2377993d45
commit ece281e708

View file

@ -17,7 +17,9 @@ import Agora.Effect (makeEffect)
import Agora.SafeMoney (AuthorityTokenTag) import Agora.SafeMoney (AuthorityTokenTag)
import Agora.Utils (psubtractSortedValue, puncurryTuple) import Agora.Utils (psubtractSortedValue, puncurryTuple)
import Generics.SOP qualified as SOP import Generics.SOP qualified as SOP
import Plutarch.Api.Internal.Hashing (hashData)
import Plutarch.Api.V1 (PCredential, PCurrencySymbol, PValue) import Plutarch.Api.V1 (PCredential, PCurrencySymbol, PValue)
import Plutarch.Api.V1.Address (PCredential (PPubKeyCredential))
import Plutarch.Api.V1.Value (pforgetPositive) import Plutarch.Api.V1.Value (pforgetPositive)
import Plutarch.Api.V2 ( import Plutarch.Api.V2 (
AmountGuarantees (Positive), AmountGuarantees (Positive),
@ -27,6 +29,7 @@ import Plutarch.Api.V2 (
PTxOut, PTxOut,
PValidator, PValidator,
) )
import Plutarch.Api.V2.Tx (POutputDatum (..))
import Plutarch.DataRepr ( import Plutarch.DataRepr (
PDataFields, PDataFields,
) )
@ -42,6 +45,7 @@ import Plutarch.Extra.Tagged (PTagged)
import Plutarch.Extra.Traversable (pfoldMap) import Plutarch.Extra.Traversable (pfoldMap)
import Plutarch.Lift (PConstantDecl, PUnsafeLiftDecl (PLifted)) import Plutarch.Lift (PConstantDecl, PUnsafeLiftDecl (PLifted))
import PlutusLedgerApi.V1.Credential (Credential) import PlutusLedgerApi.V1.Credential (Credential)
import PlutusLedgerApi.V1.Scripts (DatumHash (DatumHash))
import PlutusLedgerApi.V1.Value (Value) import PlutusLedgerApi.V1.Value (Value)
import PlutusTx qualified import PlutusTx qualified
import "liqwid-plutarch-extra" Plutarch.Extra.TermCont ( import "liqwid-plutarch-extra" Plutarch.Extra.TermCont (
@ -209,13 +213,18 @@ treasuryWithdrawalValidator = plam $
extractTreasuryOutputValue :: extractTreasuryOutputValue ::
Term _ (PTxOut :--> PValue 'Sorted 'Positive) Term _ (PTxOut :--> PValue 'Sorted 'Positive)
extractTreasuryOutputValue = plam $ extractTreasuryOutputValue = plam $
flip (pletFields @'["address", "value"]) $ \outputF -> flip (pletFields @'["address", "value", "datum"]) $ \outputF ->
let cred = pfield @"credential" # outputF.address let cred = pfield @"credential" # outputF.address
isTreasuryOutput = isTreasuryOutput =
pelem # cred # datumF.treasuries ptraceIfFalse "Should sent to one of the treasuries" $
pelem # pdata cred # datumF.treasuries
isDatumValid =
ptraceIfFalse "Valid output datum" $
checkOutputDatum # cred # outputF.datum
in pif in pif
isTreasuryOutput (isTreasuryOutput #&& isDatumValid)
outputF.value outputF.value
mempty mempty
@ -230,10 +239,11 @@ treasuryWithdrawalValidator = plam $
pure . popaque $ pconstant () pure . popaque $ pconstant ()
where where
-- Make sure that all the receivers get the correct payment and return the -- Make sure that all the receivers get the correct payment, return the
-- remaining outputs. -- remaining outputs.
--
-- This function is not hoisted cause it's used only once.
checkReceiverOutputs :: checkReceiverOutputs ::
forall (s :: S).
Term Term
s s
( PBuiltinList ( PBuiltinList
@ -245,7 +255,7 @@ treasuryWithdrawalValidator = plam $
pelimList pelimList
( \r rs -> ( \r rs ->
pelimList pelimList
( \o os -> pletFields @'["value", "address"] o $ \oF -> ( \o os -> pletFields @'["value", "address", "datum"] o $ \oF ->
let isValidReceiverOutput = let isValidReceiverOutput =
puncurryTuple puncurryTuple
# plam # plam
@ -256,6 +266,8 @@ treasuryWithdrawalValidator = plam $
expCred #== pfield @"credential" # oF.address expCred #== pfield @"credential" # oF.address
, ptraceIfFalse "Valid value" $ , ptraceIfFalse "Valid value" $
expVal #== oF.value expVal #== oF.value
, ptraceIfFalse "Valid output datum" $
checkOutputDatum # expCred # oF.datum
] ]
) )
# pfromData r # pfromData r
@ -269,3 +281,17 @@ treasuryWithdrawalValidator = plam $
) )
outputs outputs
receivers receivers
unitDatum = PlutusTx.toData ()
unitDatumHash = DatumHash $ hashData unitDatum
checkOutputDatum :: Term s (PCredential :--> POutputDatum :--> PBool)
checkOutputDatum = phoistAcyclic $ plam $ \cred datum -> pmatch cred $
\case
PPubKeyCredential _ -> pcon PTrue
_ -> pmatch datum $ \case
PNoOutputDatum _ -> pcon PFalse
POutputDatum _ -> pcon PTrue
POutputDatumHash ((pfield @"datumHash" #) -> hash) ->
pconstant unitDatumHash #== hash