add burning support to stake policy

This commit is contained in:
Emily Martins 2022-02-21 19:03:05 +01:00
parent 552c6c8a00
commit 87af9ffcb9
3 changed files with 86 additions and 25 deletions

View file

@ -1,3 +1,3 @@
name,cpu,mem,size name,cpu,mem,size
full_scripts:authorityTokenPolicy,1280339,4400,276 full_scripts:authorityTokenPolicy,1399431,4800,421
full_scripts:stakePolicy,3007173,10200,937 full_scripts:stakePolicy,3662179,12400,1572

1 name cpu mem size
2 full_scripts:authorityTokenPolicy 1280339 1399431 4400 4800 276 421
3 full_scripts:stakePolicy 3007173 3662179 10200 12400 937 1572

View file

@ -7,6 +7,7 @@ module Agora.Stake (
StakeAction (..), StakeAction (..),
Stake (..), Stake (..),
stakePolicy, stakePolicy,
stakeLocked,
) where ) where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -72,31 +73,59 @@ anyOutput ::
forall (datum :: PType) s. forall (datum :: PType) s.
( PIsData datum ( PIsData datum
) => ) =>
Term s (PTxInfo :--> (PValue :--> datum :--> PBool) :--> PBool) Term s (PTxInfo :--> (PValue :--> PAddress :--> datum :--> PBool) :--> PBool)
anyOutput = phoistAcyclic $ anyOutput = phoistAcyclic $
plam $ \txInfo' predicate -> P.do plam $ \txInfo' predicate -> P.do
txInfo <- pletFields @'["outputs"] txInfo' txInfo <- pletFields @'["outputs"] txInfo'
pany pany
# ( plam $ \txOut'' -> P.do # ( plam $ \txOut'' -> P.do
PTxOut txOut' <- pmatch (pfromData txOut'') PTxOut txOut' <- pmatch (pfromData txOut'')
txOut <- pletFields @'["value", "datumHash"] txOut' txOut <- pletFields @'["value", "datumHash", "address"] txOut'
PDJust dh <- pmatch txOut.datumHash PDJust dh <- pmatch txOut.datumHash
pmatch (pfindDatum' @datum # (pfield @"_0" # dh) # txInfo') $ \case pmatch (pfindDatum' @datum # (pfield @"_0" # dh) # txInfo') $ \case
PJust datum -> P.do PJust datum -> P.do
predicate # txOut.value # pfromData datum predicate # txOut.value # txOut.address # pfromData datum
PNothing -> pcon PFalse PNothing -> pcon PFalse
) )
# pfromData txInfo.outputs # pfromData txInfo.outputs
anyInput ::
forall (datum :: PType) s.
( PIsData datum
) =>
Term s (PTxInfo :--> (PValue :--> PAddress :--> datum :--> PBool) :--> PBool)
anyInput = phoistAcyclic $
plam $ \txInfo' predicate -> P.do
txInfo <- pletFields @'["inputs"] txInfo'
pany
# ( plam $ \txInInfo'' -> P.do
PTxInInfo txInInfo' <- pmatch (pfromData txInInfo'')
let txOut'' = pfield @"resolved" # txInInfo'
PTxOut txOut' <- pmatch (pfromData txOut'')
txOut <- pletFields @'["value", "datumHash", "address"] txOut'
PDJust dh <- pmatch txOut.datumHash
pmatch (pfindDatum' @datum # (pfield @"_0" # dh) # txInfo') $ \case
PJust datum -> P.do
predicate # txOut.value # txOut.address # pfromData datum
PNothing -> pcon PFalse
)
# pfromData txInfo.inputs
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- --
-- What this Policy does -- # What this Policy does
-- --
-- - Check that exactly 1 state thread is minted -- For minting:
-- - Check that an output exists with a state thread and a valid datum -- Check that exactly 1 state thread is minted
-- - Check that no state thread is an input -- Check that an output exists with a state thread and a valid datum
-- Check that no state thread is an input
-- --
-- Question: -- FIXME: This doesn't check that it's paid to the right script address, can we?
--
--
-- For burning:
-- Check that exactly 1 state thread is burned
-- Check that datum at state thread is valid and not locked
-- --
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
stakePolicy :: stakePolicy ::
@ -113,26 +142,57 @@ stakePolicy _stake =
PScriptContext ctx' <- pmatch ctx'' PScriptContext ctx' <- pmatch ctx''
ctx <- pletFields @'["txInfo", "purpose"] ctx' ctx <- pletFields @'["txInfo", "purpose"] ctx'
txInfo' <- plet ctx.txInfo txInfo' <- plet ctx.txInfo
txInfo <- pletFields @'["mint", "inputs"] txInfo' txInfo <- pletFields @'["mint", "inputs", "outputs"] txInfo'
PMinting ownSymbol' <- pmatch $ pfromData ctx.purpose PMinting ownSymbol' <- pmatch $ pfromData ctx.purpose
ownSymbol <- plet $ pfield @"_0" # ownSymbol' ownSymbol <- plet $ pfield @"_0" # ownSymbol'
let stValue = psingletonValue # ownSymbol # pconstant "ST" # 1 let stValue = psingletonValue # ownSymbol # pconstant "ST" # 1
passert "ST at inputs must be 0" $ stOf <- plet $ plam $ \v -> passetClassValueOf # ownSymbol # pconstant "ST" # v
(passetClassValueOf # ownSymbol # pconstant "ST" # (pvalueSpent # pfromData txInfo')) #== 0 mintedST <- plet $ stOf # txInfo.mint
inputST <- plet $ stOf # (pvalueSpent # pfromData txInfo')
passert "Minted ST must be exactly 1" $ let burning = P.do
pdata txInfo.mint #== pdata stValue passert "ST at inputs must be 1" $
inputST #== 1
passert "A UTXO must exist with the correct output" $ passert "ST burned" $
anyOutput @(StakeDatum gt) # pfromData txInfo' mintedST #== -1
# ( plam $ \value stakeDatum' -> P.do
stakeDatum <- pletFields @'["owner", "stakedAmount"] stakeDatum'
let expectedValue = paddValue # (discreteValue # stakeDatum.stakedAmount) # stValue
let ownerSignsTransaction = ptxSignedBy # ctx.txInfo # stakeDatum.owner
let valueCorrect = pdata value #== pdata expectedValue
ownerSignsTransaction #&& valueCorrect
)
pconstant () passert "An unlocked input existed containing an ST" $
anyInput @(StakeDatum gt) # pfromData txInfo'
#$ plam
$ \value _ stakeDatum' -> P.do
let hasST = stOf # value #== 1
let unlocked = pnot # (stakeLocked # stakeDatum')
hasST #&& unlocked
pconstant ()
let minting = P.do
passert "ST at inputs must be 0" $
inputST #== 0
passert "Minted ST must be exactly 1" $
mintedST #== 1
passert "A UTXO must exist with the correct output" $
anyOutput @(StakeDatum gt) # pfromData txInfo'
#$ plam
$ \value _ stakeDatum' -> P.do
stakeDatum <- pletFields @'["owner", "stakedAmount"] stakeDatum'
let expectedValue = paddValue # (discreteValue # stakeDatum.stakedAmount) # stValue
let ownerSignsTransaction = ptxSignedBy # ctx.txInfo # stakeDatum.owner
let valueCorrect = pdata value #== pdata expectedValue -- TODO: Needs to be >=, rather than ==
ownerSignsTransaction #&& valueCorrect
pconstant ()
pif (0 #< mintedST) minting burning
-- | Check whether a Stake is locked. If it is locked, various actions are unavailable.
stakeLocked :: forall (gt :: MoneyClass) s. Term s (StakeDatum gt :--> PBool)
stakeLocked = phoistAcyclic $
plam $ \_stakeDatum ->
-- TODO: when we extend this to support proposals, this will need to do something
pcon PFalse

View file

@ -107,6 +107,7 @@ passetClassValueOf =
v <- pexpectJust 0 (plookup # pdata token # m) v <- pexpectJust 0 (plookup # pdata token # m)
pfromData v pfromData v
-- | Extract amount from PValue belonging to a Haskell-level AssetClass
passetClassValueOf' :: AssetClass -> Term s (PValue :--> PInteger) passetClassValueOf' :: AssetClass -> Term s (PValue :--> PInteger)
passetClassValueOf' (AssetClass (sym, token)) = passetClassValueOf' (AssetClass (sym, token)) =
passetClassValueOf # pconstant sym # pconstant token passetClassValueOf # pconstant sym # pconstant token