tests for destroying stakes
This commit is contained in:
parent
1557067b76
commit
561cc6c378
3 changed files with 341 additions and 1 deletions
297
agora-specs/Sample/Stake/Destroy.hs
Normal file
297
agora-specs/Sample/Stake/Destroy.hs
Normal file
|
|
@ -0,0 +1,297 @@
|
||||||
|
module Sample.Stake.Destroy (
|
||||||
|
ParameterBundle (..),
|
||||||
|
StakeInputParameters (..),
|
||||||
|
StakeBurningParameters (..),
|
||||||
|
LeftOverStakeMode (..),
|
||||||
|
AuthorizedBy (..),
|
||||||
|
Validity (..),
|
||||||
|
destroy,
|
||||||
|
mkTestTree,
|
||||||
|
mkTotallyValid,
|
||||||
|
oneStake,
|
||||||
|
multipleStakes,
|
||||||
|
stealSST,
|
||||||
|
stealSST1,
|
||||||
|
stealSST3,
|
||||||
|
lockedStakes,
|
||||||
|
authorizedByDelegatee,
|
||||||
|
notAuthorized,
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Agora.Proposal (ProposalId (..))
|
||||||
|
import Agora.Stake (
|
||||||
|
ProposalLock (Created),
|
||||||
|
StakeDatum (..),
|
||||||
|
StakeRedeemer (Destroy),
|
||||||
|
)
|
||||||
|
import Control.Exception (assert)
|
||||||
|
import Data.Maybe (catMaybes, fromJust)
|
||||||
|
import Data.Semigroup (stimesMonoid)
|
||||||
|
import Plutarch.Context (
|
||||||
|
input,
|
||||||
|
mint,
|
||||||
|
normalizeValue,
|
||||||
|
output,
|
||||||
|
pubKey,
|
||||||
|
script,
|
||||||
|
signedWith,
|
||||||
|
withDatum,
|
||||||
|
withRedeemer,
|
||||||
|
withRef,
|
||||||
|
withValue,
|
||||||
|
)
|
||||||
|
import Plutarch.Extra.AssetClass (assetClassValue)
|
||||||
|
import PlutusLedgerApi.V1 (
|
||||||
|
Credential (PubKeyCredential),
|
||||||
|
TxOutRef (TxOutRef),
|
||||||
|
)
|
||||||
|
import PlutusLedgerApi.V2 (PubKeyHash)
|
||||||
|
import Sample.Proposal.Shared (stakeTxRef)
|
||||||
|
import Sample.Shared (
|
||||||
|
minAda,
|
||||||
|
signer2,
|
||||||
|
stakeAssetClass,
|
||||||
|
stakePolicy,
|
||||||
|
stakeSymbol,
|
||||||
|
stakeValidator,
|
||||||
|
stakeValidatorHash,
|
||||||
|
)
|
||||||
|
import Test.Specification (
|
||||||
|
SpecificationTree,
|
||||||
|
group,
|
||||||
|
testPolicy,
|
||||||
|
testValidator,
|
||||||
|
)
|
||||||
|
import Test.Util (CombinableBuilder, mkMinting, mkSpending, pubKeyHashes)
|
||||||
|
|
||||||
|
data ParameterBundle = ParameterBundle
|
||||||
|
{ stakeInputParameters :: StakeInputParameters
|
||||||
|
, stakeBurningParameters :: StakeBurningParameters
|
||||||
|
, authorizedBy :: AuthorizedBy
|
||||||
|
}
|
||||||
|
|
||||||
|
data StakeInputParameters = StakeInputParameters
|
||||||
|
{ numInputs :: Int
|
||||||
|
, notUnlocked :: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
data StakeBurningParameters = StakeBurningParameters
|
||||||
|
{ numBurnt :: Int
|
||||||
|
, leftOverStakeMode :: Maybe LeftOverStakeMode
|
||||||
|
}
|
||||||
|
|
||||||
|
data LeftOverStakeMode = OutputAsIs | CollectSSTInOneUTxO
|
||||||
|
|
||||||
|
data AuthorizedBy = Owner | Delegatee | NotAuthorized
|
||||||
|
|
||||||
|
data Validity = Validity
|
||||||
|
{ forStakePolicy :: Maybe Bool
|
||||||
|
, forStakeValidator :: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
owner :: PubKeyHash
|
||||||
|
owner = pubKeyHashes !! 2
|
||||||
|
|
||||||
|
delegatee :: PubKeyHash
|
||||||
|
delegatee = pubKeyHashes !! 3
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
mkStakeInputDatum :: StakeInputParameters -> StakeDatum
|
||||||
|
mkStakeInputDatum ps =
|
||||||
|
StakeDatum
|
||||||
|
{ stakedAmount = 114514
|
||||||
|
, owner = PubKeyCredential owner
|
||||||
|
, delegatedTo = Just $ PubKeyCredential delegatee
|
||||||
|
, lockedBy = [Created $ ProposalId 0 | ps.notUnlocked]
|
||||||
|
}
|
||||||
|
|
||||||
|
mkStakeRef :: Int -> TxOutRef
|
||||||
|
mkStakeRef = TxOutRef stakeTxRef . fromIntegral
|
||||||
|
|
||||||
|
stakeRedeemer :: StakeRedeemer
|
||||||
|
stakeRedeemer = Destroy
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
destroy :: forall b. CombinableBuilder b => ParameterBundle -> b
|
||||||
|
destroy ps =
|
||||||
|
let stakeInputDatum = mkStakeInputDatum ps.stakeInputParameters
|
||||||
|
|
||||||
|
sst = assetClassValue stakeAssetClass 1
|
||||||
|
|
||||||
|
stakeUTxOTemplate =
|
||||||
|
mconcat
|
||||||
|
[ script stakeValidatorHash
|
||||||
|
, withDatum stakeInputDatum
|
||||||
|
, withValue $ normalizeValue $ sst <> minAda
|
||||||
|
]
|
||||||
|
|
||||||
|
stakeInputBuilder =
|
||||||
|
foldMap
|
||||||
|
( \i ->
|
||||||
|
input $
|
||||||
|
mconcat
|
||||||
|
[ stakeUTxOTemplate
|
||||||
|
, withRef $ mkStakeRef i
|
||||||
|
, withRedeemer stakeRedeemer
|
||||||
|
]
|
||||||
|
)
|
||||||
|
[1 .. ps.stakeInputParameters.numInputs]
|
||||||
|
|
||||||
|
withSSTsBurnt =
|
||||||
|
mint $
|
||||||
|
normalizeValue $
|
||||||
|
assetClassValue stakeAssetClass $
|
||||||
|
negate $
|
||||||
|
fromIntegral ps.stakeBurningParameters.numBurnt
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
leftOverStakes =
|
||||||
|
ps.stakeInputParameters.numInputs
|
||||||
|
- ps.stakeBurningParameters.numBurnt
|
||||||
|
|
||||||
|
stealSSTs =
|
||||||
|
case fromJust ps.stakeBurningParameters.leftOverStakeMode of
|
||||||
|
OutputAsIs ->
|
||||||
|
foldMap output $
|
||||||
|
replicate
|
||||||
|
leftOverStakes
|
||||||
|
stakeUTxOTemplate
|
||||||
|
CollectSSTInOneUTxO ->
|
||||||
|
output $
|
||||||
|
mconcat
|
||||||
|
[ pubKey signer2
|
||||||
|
, withValue $ stimesMonoid leftOverStakes sst
|
||||||
|
]
|
||||||
|
|
||||||
|
stakeOutputBuilder =
|
||||||
|
assert (leftOverStakes >= 0) $
|
||||||
|
mconcat
|
||||||
|
[ withSSTsBurnt
|
||||||
|
, if leftOverStakes > 0
|
||||||
|
then stealSSTs
|
||||||
|
else mempty
|
||||||
|
]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
sigBuilder = case ps.authorizedBy of
|
||||||
|
Owner -> signedWith owner
|
||||||
|
Delegatee -> signedWith delegatee
|
||||||
|
NotAuthorized -> mempty
|
||||||
|
in mconcat
|
||||||
|
[ stakeInputBuilder
|
||||||
|
, stakeOutputBuilder
|
||||||
|
, sigBuilder
|
||||||
|
]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
mkTestTree ::
|
||||||
|
String ->
|
||||||
|
ParameterBundle ->
|
||||||
|
Validity ->
|
||||||
|
SpecificationTree
|
||||||
|
mkTestTree name pb val = group name $ catMaybes [validator, policy]
|
||||||
|
where
|
||||||
|
spend = mkSpending destroy pb
|
||||||
|
mint = mkMinting destroy pb
|
||||||
|
validator =
|
||||||
|
Just $
|
||||||
|
testValidator
|
||||||
|
val.forStakeValidator
|
||||||
|
"stake validator"
|
||||||
|
stakeValidator
|
||||||
|
(mkStakeInputDatum pb.stakeInputParameters)
|
||||||
|
stakeRedeemer
|
||||||
|
(spend $ mkStakeRef 1)
|
||||||
|
|
||||||
|
policy = case pb.stakeBurningParameters.numBurnt of
|
||||||
|
0 -> Nothing
|
||||||
|
_ ->
|
||||||
|
Just $
|
||||||
|
testPolicy
|
||||||
|
(fromJust val.forStakePolicy)
|
||||||
|
"stake policy"
|
||||||
|
stakePolicy
|
||||||
|
()
|
||||||
|
(mint stakeSymbol)
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
mkTotallyValid :: Int -> ParameterBundle
|
||||||
|
mkTotallyValid numStakes =
|
||||||
|
ParameterBundle
|
||||||
|
{ stakeInputParameters =
|
||||||
|
StakeInputParameters
|
||||||
|
{ numInputs = numStakes
|
||||||
|
, notUnlocked = False
|
||||||
|
}
|
||||||
|
, stakeBurningParameters =
|
||||||
|
StakeBurningParameters
|
||||||
|
{ numBurnt = numStakes
|
||||||
|
, leftOverStakeMode = Nothing
|
||||||
|
}
|
||||||
|
, authorizedBy = Owner
|
||||||
|
}
|
||||||
|
|
||||||
|
oneStake :: ParameterBundle
|
||||||
|
oneStake = mkTotallyValid 1
|
||||||
|
|
||||||
|
multipleStakes :: ParameterBundle
|
||||||
|
multipleStakes = mkTotallyValid 10
|
||||||
|
|
||||||
|
stealSST :: ParameterBundle
|
||||||
|
stealSST =
|
||||||
|
multipleStakes
|
||||||
|
{ stakeBurningParameters =
|
||||||
|
StakeBurningParameters
|
||||||
|
{ numBurnt = 1
|
||||||
|
, leftOverStakeMode = Just CollectSSTInOneUTxO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stealSST1 :: ParameterBundle
|
||||||
|
stealSST1 =
|
||||||
|
multipleStakes
|
||||||
|
{ stakeBurningParameters =
|
||||||
|
StakeBurningParameters
|
||||||
|
{ numBurnt = 0
|
||||||
|
, leftOverStakeMode = Just CollectSSTInOneUTxO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stealSST3 :: ParameterBundle
|
||||||
|
stealSST3 =
|
||||||
|
multipleStakes
|
||||||
|
{ stakeBurningParameters =
|
||||||
|
StakeBurningParameters
|
||||||
|
{ numBurnt = 1
|
||||||
|
, leftOverStakeMode = Just OutputAsIs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lockedStakes :: ParameterBundle
|
||||||
|
lockedStakes =
|
||||||
|
multipleStakes
|
||||||
|
{ stakeInputParameters =
|
||||||
|
multipleStakes.stakeInputParameters
|
||||||
|
{ notUnlocked = True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
authorizedByDelegatee :: ParameterBundle
|
||||||
|
authorizedByDelegatee =
|
||||||
|
multipleStakes
|
||||||
|
{ authorizedBy = Delegatee
|
||||||
|
}
|
||||||
|
|
||||||
|
notAuthorized :: ParameterBundle
|
||||||
|
notAuthorized =
|
||||||
|
multipleStakes
|
||||||
|
{ authorizedBy = NotAuthorized
|
||||||
|
}
|
||||||
|
|
@ -27,6 +27,7 @@ import Sample.Stake qualified as Stake (
|
||||||
stakeDepositWithdraw,
|
stakeDepositWithdraw,
|
||||||
)
|
)
|
||||||
import Sample.Stake.Create qualified as Create
|
import Sample.Stake.Create qualified as Create
|
||||||
|
import Sample.Stake.Destroy qualified as Destroy
|
||||||
import Sample.Stake.SetDelegate qualified as SetDelegate
|
import Sample.Stake.SetDelegate qualified as SetDelegate
|
||||||
import Test.Specification (
|
import Test.Specification (
|
||||||
SpecificationTree,
|
SpecificationTree,
|
||||||
|
|
@ -92,7 +93,48 @@ specs =
|
||||||
]
|
]
|
||||||
, group
|
, group
|
||||||
"validator"
|
"validator"
|
||||||
[ validatorSucceedsWith
|
[ group
|
||||||
|
"destroy"
|
||||||
|
[ group
|
||||||
|
"legal"
|
||||||
|
[ Destroy.mkTestTree
|
||||||
|
"One stake"
|
||||||
|
Destroy.oneStake
|
||||||
|
(Destroy.Validity (Just True) True)
|
||||||
|
, Destroy.mkTestTree
|
||||||
|
"Multiple stake"
|
||||||
|
Destroy.multipleStakes
|
||||||
|
(Destroy.Validity (Just True) True)
|
||||||
|
]
|
||||||
|
, group
|
||||||
|
"illegal"
|
||||||
|
[ Destroy.mkTestTree
|
||||||
|
"Destroy only one stake to steal SST"
|
||||||
|
Destroy.stealSST
|
||||||
|
(Destroy.Validity (Just False) False)
|
||||||
|
, Destroy.mkTestTree
|
||||||
|
"Destroy nothing to steal SST"
|
||||||
|
Destroy.stealSST1
|
||||||
|
(Destroy.Validity Nothing False)
|
||||||
|
, Destroy.mkTestTree
|
||||||
|
"Steal SST"
|
||||||
|
Destroy.stealSST3
|
||||||
|
(Destroy.Validity (Just False) False)
|
||||||
|
, Destroy.mkTestTree
|
||||||
|
"Destroy locked stakes"
|
||||||
|
Destroy.lockedStakes
|
||||||
|
(Destroy.Validity (Just False) False)
|
||||||
|
, Destroy.mkTestTree
|
||||||
|
"not authorized by owner"
|
||||||
|
Destroy.notAuthorized
|
||||||
|
(Destroy.Validity (Just True) False)
|
||||||
|
, Destroy.mkTestTree
|
||||||
|
"not authorized by owner"
|
||||||
|
Destroy.authorizedByDelegatee
|
||||||
|
(Destroy.Validity (Just True) False)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, validatorSucceedsWith
|
||||||
"stakeDepositWithdraw deposit"
|
"stakeDepositWithdraw deposit"
|
||||||
stakeValidator
|
stakeValidator
|
||||||
(StakeDatum 100_000 (PubKeyCredential signer) Nothing [])
|
(StakeDatum 100_000 (PubKeyCredential signer) Nothing [])
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,7 @@ library agora-specs
|
||||||
Sample.Shared
|
Sample.Shared
|
||||||
Sample.Stake
|
Sample.Stake
|
||||||
Sample.Stake.Create
|
Sample.Stake.Create
|
||||||
|
Sample.Stake.Destroy
|
||||||
Sample.Stake.SetDelegate
|
Sample.Stake.SetDelegate
|
||||||
Sample.Treasury
|
Sample.Treasury
|
||||||
Spec.AuthorityToken
|
Spec.AuthorityToken
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue