commit ec70bfd539fe2e27fd48f5f76395400287ac72d7
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Tue Oct 18 18:58:59 2022 -0500
use LSE
commit 25fff9b3ad1f2dde4cd7cf36977530b06a87d23c
Merge: 01cd3aa 1821dd6
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Tue Oct 18 18:17:45 2022 -0500
Merge branch 'staging' into seungheonoh/ply
commit 01cd3aa7a235e6fe6658246ca1026fa26dc71a83
Author: Hongrui Fang <chfanghr@gmail.com>
Date: Tue Oct 11 12:02:03 2022 +0800
update benchmark
commit a8513244892ce33cfdc9edf8cd501c4985ae8008
Author: Hongrui Fang <chfanghr@gmail.com>
Date: Tue Oct 11 11:59:22 2022 +0800
fix tests
commit 20ca40823485c2e2f78253643cf4453ac7b7ddd5
Author: Hongrui Fang <chfanghr@gmail.com>
Date: Tue Oct 11 11:57:37 2022 +0800
better import
commit a19fe49424210891bd03db71e4083fc1e0edfd98
Author: Hongrui Fang <chfanghr@gmail.com>
Date: Tue Oct 11 11:08:20 2022 +0800
update flake inputs
commit c93b21f1f9441e5c6f54525bf7c6a54757ec36cc
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Mon Oct 10 12:54:12 2022 -0500
tried to make tests pass
commit 1046ae1237299a33c58b48661bdb6d325a22147e
Merge: 2bf4e36 363bd83
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Mon Oct 10 12:18:48 2022 -0500
Merge branch 'staging' into seungheonoh/ply
commit 2bf4e3627c1b229f58078695082da85c80efd560
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Mon Oct 10 10:48:36 2022 -0500
remove junkpile
commit a1dbc9ad9e531fe0d0a0480c4aef9cf9ffa90f1d
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Mon Oct 10 10:47:25 2022 -0500
versions
commit 4542a06ac733858297d3a48c53368fad19dedc43
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Thu Oct 6 22:57:48 2022 -0500
script exporting interface
commit 6bd8c1a1d57e4bf9dc25c3068a9c8eae6bf6a19d
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Thu Oct 6 22:58:41 2022 -0500
fixed tests
commit d3ce2cf95633d336f3e621833677bd5bf10ee2c8
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Sun Oct 2 00:55:18 2022 -0500
fixed tests
commit 1ae64c9f692652b77b0506013853b2ba44267c65
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Sat Oct 1 13:28:20 2022 -0500
linker
commit db88cb75c7b74843141ad8ab4e6522b66d0dcfbc
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Sat Oct 1 01:03:50 2022 -0500
exporting scripts
commit 6389fce28e885a8a7f8669629c266f59c0edb51f
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Sat Oct 1 00:51:49 2022 -0500
made scripts parameterized on the script level
commit aea1e518a8890550bdebd0e5251da11d915c53a9
Author: Seungheon Oh <seungheon.ooh@gmail.com>
Date: Wed Sep 28 19:53:29 2022 -0500
Use `TypedScriptEnvelope` for `Agora.Bootstrap`
420 lines
10 KiB
Haskell
420 lines
10 KiB
Haskell
{- |
|
|
Module : Sample.Proposal.Cosign
|
|
Maintainer : connor@mlabs.city
|
|
Description: Generate sample data for testing the functionalities of cosigning proposals
|
|
|
|
Sample and utilities for testing the functionalities of cosigning proposals.
|
|
-}
|
|
module Sample.Proposal.Cosign (
|
|
StakedAmount (..),
|
|
StakeOwner (..),
|
|
StakeParameters (..),
|
|
SignedBy (..),
|
|
TransactionParameters (..),
|
|
ProposalParameters (..),
|
|
ParameterBundle (..),
|
|
Validity (..),
|
|
cosign,
|
|
mkTestTree,
|
|
totallyValid,
|
|
insufficientStakedAmount,
|
|
duplicateCosigners,
|
|
locksNotUpdated,
|
|
cosignersNotUpdated,
|
|
cosignAfterDraft,
|
|
) where
|
|
|
|
import Agora.Governor (Governor (..))
|
|
import Agora.Proposal (
|
|
ProposalDatum (..),
|
|
ProposalId (ProposalId),
|
|
ProposalRedeemer (Cosign),
|
|
ProposalStatus (..),
|
|
ProposalThresholds (..),
|
|
ResultTag (ResultTag),
|
|
emptyVotesFor,
|
|
)
|
|
import Agora.Proposal.Time (
|
|
ProposalStartingTime (ProposalStartingTime),
|
|
ProposalTimingConfig (draftTime),
|
|
)
|
|
import Agora.SafeMoney (GTTag)
|
|
import Agora.Stake (
|
|
ProposalLock (Cosigned, Created),
|
|
StakeDatum (..),
|
|
StakeRedeemer (PermitVote),
|
|
)
|
|
import Data.Coerce (coerce)
|
|
import Data.Default (def)
|
|
import Data.List (sort)
|
|
import Data.Map.Strict qualified as StrictMap
|
|
import Data.Tagged (untag)
|
|
import Plutarch.Context (
|
|
input,
|
|
normalizeValue,
|
|
output,
|
|
script,
|
|
signedWith,
|
|
timeRange,
|
|
txId,
|
|
withDatum,
|
|
withInlineDatum,
|
|
withRedeemer,
|
|
withRef,
|
|
withValue,
|
|
)
|
|
import Plutarch.SafeMoney (Discrete (Discrete))
|
|
import PlutusLedgerApi.V1.Value qualified as Value
|
|
import PlutusLedgerApi.V2 (
|
|
Credential (PubKeyCredential),
|
|
POSIXTime (POSIXTime),
|
|
PubKeyHash,
|
|
TxOutRef (TxOutRef),
|
|
)
|
|
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef)
|
|
import Sample.Shared (
|
|
fromDiscrete,
|
|
governor,
|
|
minAda,
|
|
proposalPolicySymbol,
|
|
proposalValidator,
|
|
proposalValidatorHash,
|
|
stakeAssetClass,
|
|
stakeValidator,
|
|
stakeValidatorHash,
|
|
)
|
|
import Test.Specification (
|
|
SpecificationTree,
|
|
group,
|
|
testValidator,
|
|
)
|
|
import Test.Util (
|
|
CombinableBuilder,
|
|
closedBoundedInterval,
|
|
mkSpending,
|
|
pubKeyHashes,
|
|
)
|
|
|
|
data StakedAmount = Sufficient | Insufficient
|
|
|
|
data StakeOwner = Creator | Other
|
|
|
|
data StakeParameters = StakeParameters
|
|
{ gtAmount :: StakedAmount
|
|
, stakeOwner :: StakeOwner
|
|
, dontUpdateLocks :: Bool
|
|
}
|
|
|
|
data SignedBy = Owner | Delegatee | Unknown
|
|
|
|
newtype TransactionParameters = TransactionParameters
|
|
{ signedBy :: SignedBy
|
|
}
|
|
|
|
data ProposalParameters = ProposalParameters
|
|
{ proposalStatus :: ProposalStatus
|
|
, dontUpdateCosigners :: Bool
|
|
}
|
|
|
|
-- | Parameters for cosigning a proposal.
|
|
data ParameterBundle = ParameterBundle
|
|
{ stakeParameters :: StakeParameters
|
|
, proposalParameters :: ProposalParameters
|
|
, transactionParameters :: TransactionParameters
|
|
}
|
|
|
|
data Validity = Validity
|
|
{ forProposalValidator :: Bool
|
|
, forStakeValidator :: Bool
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
mkStakeAmount :: StakedAmount -> Discrete GTTag
|
|
mkStakeAmount Sufficient = Discrete $ (def @ProposalThresholds).cosign
|
|
mkStakeAmount Insufficient = mkStakeAmount Sufficient - 1
|
|
|
|
mkStakeOwner :: StakeOwner -> PubKeyHash
|
|
mkStakeOwner Creator = creator
|
|
mkStakeOwner Other = pubKeyHashes !! 2
|
|
|
|
mkSigner :: StakeOwner -> SignedBy -> PubKeyHash
|
|
mkSigner so Owner = mkStakeOwner so
|
|
mkSigner _ Delegatee = delegatee
|
|
mkSigner _ Unknown = pubKeyHashes !! 4
|
|
|
|
creator :: PubKeyHash
|
|
creator = pubKeyHashes !! 1
|
|
|
|
delegatee :: PubKeyHash
|
|
delegatee = pubKeyHashes !! 3
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
defProposalId :: ProposalId
|
|
defProposalId = ProposalId 0
|
|
|
|
mkProposalInputDatum :: ParameterBundle -> ProposalDatum
|
|
mkProposalInputDatum ps =
|
|
let effects =
|
|
StrictMap.fromList
|
|
[ (ResultTag 0, StrictMap.empty)
|
|
, (ResultTag 1, StrictMap.empty)
|
|
]
|
|
in ProposalDatum
|
|
{ proposalId = ProposalId 0
|
|
, effects = effects
|
|
, status = ps.proposalParameters.proposalStatus
|
|
, cosigners = [PubKeyCredential creator]
|
|
, thresholds = def
|
|
, votes = emptyVotesFor effects
|
|
, timingConfig = def
|
|
, startingTime = ProposalStartingTime 0
|
|
}
|
|
|
|
mkProposalOutputDatum :: ParameterBundle -> ProposalDatum
|
|
mkProposalOutputDatum ps =
|
|
let inputDatum = mkProposalInputDatum ps
|
|
stakeOwner =
|
|
PubKeyCredential $
|
|
mkStakeOwner ps.stakeParameters.stakeOwner
|
|
newCosigners =
|
|
if ps.proposalParameters.dontUpdateCosigners
|
|
then inputDatum.cosigners
|
|
else sort $ stakeOwner : inputDatum.cosigners
|
|
in inputDatum {cosigners = newCosigners}
|
|
|
|
proposalRedeemer :: ProposalRedeemer
|
|
proposalRedeemer = Cosign
|
|
|
|
proposalRef :: TxOutRef
|
|
proposalRef = TxOutRef proposalTxRef 1
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
mkStakeInputDatum :: ParameterBundle -> StakeDatum
|
|
mkStakeInputDatum ps =
|
|
let sps = ps.stakeParameters
|
|
amount = mkStakeAmount sps.gtAmount
|
|
owner = mkStakeOwner sps.stakeOwner
|
|
locks = case sps.stakeOwner of
|
|
Creator -> [Created defProposalId]
|
|
_ -> []
|
|
in StakeDatum
|
|
{ stakedAmount = amount
|
|
, owner = PubKeyCredential owner
|
|
, delegatedTo = Just $ PubKeyCredential delegatee
|
|
, lockedBy = locks
|
|
}
|
|
|
|
mkStakeOuputDatum :: ParameterBundle -> StakeDatum
|
|
mkStakeOuputDatum ps =
|
|
let sps = ps.stakeParameters
|
|
inpDatum = mkStakeInputDatum ps
|
|
locks =
|
|
if sps.dontUpdateLocks
|
|
then inpDatum.lockedBy
|
|
else Cosigned defProposalId : inpDatum.lockedBy
|
|
in inpDatum {lockedBy = locks}
|
|
|
|
stakeRedeemer :: StakeRedeemer
|
|
stakeRedeemer = PermitVote
|
|
|
|
stakeRef :: TxOutRef
|
|
stakeRef = TxOutRef stakeTxRef 0
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Create a 'TxInfo' that tries to cosign a proposal with new cosigners.
|
|
cosign :: forall b. CombinableBuilder b => ParameterBundle -> b
|
|
cosign ps = builder
|
|
where
|
|
pst = Value.singleton proposalPolicySymbol "" 1
|
|
sst = Value.assetClassValue stakeAssetClass 1
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
stakeInputDatum = mkStakeInputDatum ps
|
|
stakeOutputDatum = mkStakeOuputDatum ps
|
|
|
|
stakeValue =
|
|
normalizeValue $
|
|
minAda
|
|
<> Value.assetClassValue
|
|
(untag governor.gtClassRef)
|
|
( fromDiscrete $
|
|
mkStakeAmount ps.stakeParameters.gtAmount
|
|
)
|
|
<> sst
|
|
|
|
stakeBuilder =
|
|
mconcat
|
|
[ input $
|
|
mconcat
|
|
[ script stakeValidatorHash
|
|
, withValue stakeValue
|
|
, withInlineDatum stakeInputDatum
|
|
, withRef stakeRef
|
|
, withRedeemer stakeRedeemer
|
|
]
|
|
, output $
|
|
mconcat
|
|
[ script stakeValidatorHash
|
|
, withValue stakeValue
|
|
, withInlineDatum stakeOutputDatum
|
|
]
|
|
]
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
proposalInputDatum = mkProposalInputDatum ps
|
|
proposalOutputDatum = mkProposalOutputDatum ps
|
|
|
|
proposalValue =
|
|
normalizeValue $
|
|
pst <> minAda
|
|
|
|
proposalBuilder =
|
|
mconcat
|
|
[ input $
|
|
mconcat
|
|
[ script proposalValidatorHash
|
|
, withValue proposalValue
|
|
, withDatum proposalInputDatum
|
|
, withRef proposalRef
|
|
, withRedeemer proposalRedeemer
|
|
]
|
|
, output $
|
|
mconcat
|
|
[ script proposalValidatorHash
|
|
, withValue proposalValue
|
|
, withDatum proposalOutputDatum
|
|
]
|
|
]
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
validTimeRange =
|
|
closedBoundedInterval
|
|
(coerce proposalInputDatum.startingTime + 1)
|
|
( coerce proposalInputDatum.startingTime
|
|
+ proposalInputDatum.timingConfig.draftTime - 1
|
|
)
|
|
|
|
sig =
|
|
mkSigner
|
|
ps.stakeParameters.stakeOwner
|
|
ps.transactionParameters.signedBy
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
builder =
|
|
mconcat
|
|
[ txId "05c67819fc3381a2052b929ab439244b7b5fe3b3bd07f2134055bbbb21bd9e52"
|
|
, timeRange validTimeRange
|
|
, proposalBuilder
|
|
, stakeBuilder
|
|
, signedWith sig
|
|
]
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
mkTestTree ::
|
|
String ->
|
|
ParameterBundle ->
|
|
Validity ->
|
|
SpecificationTree
|
|
mkTestTree name ps val =
|
|
group name [proposal, stake]
|
|
where
|
|
spend = mkSpending cosign ps
|
|
|
|
proposal =
|
|
testValidator
|
|
val.forProposalValidator
|
|
"proposal"
|
|
proposalValidator
|
|
(mkProposalInputDatum ps)
|
|
proposalRedeemer
|
|
(spend proposalRef)
|
|
|
|
stake =
|
|
testValidator
|
|
val.forStakeValidator
|
|
"stake"
|
|
stakeValidator
|
|
(mkStakeInputDatum ps)
|
|
stakeRedeemer
|
|
(spend stakeRef)
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
totallyValid :: ParameterBundle
|
|
totallyValid =
|
|
ParameterBundle
|
|
{ stakeParameters =
|
|
StakeParameters
|
|
{ gtAmount = Sufficient
|
|
, stakeOwner = Other
|
|
, dontUpdateLocks = False
|
|
}
|
|
, proposalParameters =
|
|
ProposalParameters
|
|
{ proposalStatus = Draft
|
|
, dontUpdateCosigners = False
|
|
}
|
|
, transactionParameters =
|
|
TransactionParameters
|
|
{ signedBy =
|
|
Owner
|
|
}
|
|
}
|
|
|
|
insufficientStakedAmount :: ParameterBundle
|
|
insufficientStakedAmount =
|
|
totallyValid
|
|
{ stakeParameters =
|
|
totallyValid.stakeParameters
|
|
{ gtAmount = Insufficient
|
|
}
|
|
}
|
|
|
|
locksNotUpdated :: ParameterBundle
|
|
locksNotUpdated =
|
|
totallyValid
|
|
{ stakeParameters =
|
|
totallyValid.stakeParameters
|
|
{ dontUpdateLocks = True
|
|
}
|
|
}
|
|
|
|
duplicateCosigners :: ParameterBundle
|
|
duplicateCosigners =
|
|
totallyValid
|
|
{ stakeParameters =
|
|
totallyValid.stakeParameters
|
|
{ stakeOwner = Creator
|
|
}
|
|
}
|
|
|
|
cosignersNotUpdated :: ParameterBundle
|
|
cosignersNotUpdated =
|
|
totallyValid
|
|
{ proposalParameters =
|
|
totallyValid.proposalParameters
|
|
{ dontUpdateCosigners = True
|
|
}
|
|
}
|
|
|
|
cosignAfterDraft :: [ParameterBundle]
|
|
cosignAfterDraft =
|
|
map
|
|
( \s ->
|
|
totallyValid
|
|
{ proposalParameters =
|
|
totallyValid.proposalParameters
|
|
{ proposalStatus = s
|
|
}
|
|
}
|
|
)
|
|
[VotingReady, Locked, Finished]
|