add tests and samples of advancing proposals
This commit is contained in:
parent
9e8424b458
commit
042c18a382
8 changed files with 626 additions and 35 deletions
|
|
@ -45,7 +45,6 @@ import Plutus.V1.Ledger.Value qualified as Value
|
||||||
|
|
||||||
import Sample.Shared (
|
import Sample.Shared (
|
||||||
authorityTokenSymbol,
|
authorityTokenSymbol,
|
||||||
defaultProposalThresholds,
|
|
||||||
govAssetClass,
|
govAssetClass,
|
||||||
govValidatorAddress,
|
govValidatorAddress,
|
||||||
governor,
|
governor,
|
||||||
|
|
@ -113,7 +112,7 @@ mkEffectTxInfo newGovDatum =
|
||||||
governorInputDatum' :: GovernorDatum
|
governorInputDatum' :: GovernorDatum
|
||||||
governorInputDatum' =
|
governorInputDatum' =
|
||||||
GovernorDatum
|
GovernorDatum
|
||||||
{ proposalThresholds = defaultProposalThresholds
|
{ proposalThresholds = def
|
||||||
, nextProposalId = ProposalId 0
|
, nextProposalId = ProposalId 0
|
||||||
, proposalTimings = def
|
, proposalTimings = def
|
||||||
, createProposalTimeRangeMaxWidth = def
|
, createProposalTimeRangeMaxWidth = def
|
||||||
|
|
@ -175,7 +174,7 @@ mkEffectTxInfo newGovDatum =
|
||||||
validNewGovernorDatum :: GovernorDatum
|
validNewGovernorDatum :: GovernorDatum
|
||||||
validNewGovernorDatum =
|
validNewGovernorDatum =
|
||||||
GovernorDatum
|
GovernorDatum
|
||||||
{ proposalThresholds = defaultProposalThresholds
|
{ proposalThresholds = def
|
||||||
, nextProposalId = ProposalId 42
|
, nextProposalId = ProposalId 42
|
||||||
, proposalTimings = def
|
, proposalTimings = def
|
||||||
, createProposalTimeRangeMaxWidth = def
|
, createProposalTimeRangeMaxWidth = def
|
||||||
|
|
@ -185,7 +184,7 @@ invalidNewGovernorDatum :: GovernorDatum
|
||||||
invalidNewGovernorDatum =
|
invalidNewGovernorDatum =
|
||||||
GovernorDatum
|
GovernorDatum
|
||||||
{ proposalThresholds =
|
{ proposalThresholds =
|
||||||
defaultProposalThresholds
|
def
|
||||||
{ countVoting = Tagged (-1)
|
{ countVoting = Tagged (-1)
|
||||||
}
|
}
|
||||||
, nextProposalId = ProposalId 42
|
, nextProposalId = ProposalId 42
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,6 @@ import Agora.Stake (
|
||||||
|
|
||||||
import Sample.Shared (
|
import Sample.Shared (
|
||||||
authorityTokenSymbol,
|
authorityTokenSymbol,
|
||||||
defaultProposalThresholds,
|
|
||||||
govAssetClass,
|
govAssetClass,
|
||||||
govSymbol,
|
govSymbol,
|
||||||
govValidatorAddress,
|
govValidatorAddress,
|
||||||
|
|
@ -119,7 +118,7 @@ mintGST =
|
||||||
governorOutputDatum' :: GovernorDatum
|
governorOutputDatum' :: GovernorDatum
|
||||||
governorOutputDatum' =
|
governorOutputDatum' =
|
||||||
GovernorDatum
|
GovernorDatum
|
||||||
{ proposalThresholds = defaultProposalThresholds
|
{ proposalThresholds = def
|
||||||
, nextProposalId = ProposalId 0
|
, nextProposalId = ProposalId 0
|
||||||
, proposalTimings = def
|
, proposalTimings = def
|
||||||
, createProposalTimeRangeMaxWidth = def
|
, createProposalTimeRangeMaxWidth = def
|
||||||
|
|
@ -214,7 +213,7 @@ createProposal =
|
||||||
governorInputDatum' :: GovernorDatum
|
governorInputDatum' :: GovernorDatum
|
||||||
governorInputDatum' =
|
governorInputDatum' =
|
||||||
GovernorDatum
|
GovernorDatum
|
||||||
{ proposalThresholds = defaultProposalThresholds
|
{ proposalThresholds = def
|
||||||
, nextProposalId = thisProposalId
|
, nextProposalId = thisProposalId
|
||||||
, proposalTimings = def
|
, proposalTimings = def
|
||||||
, createProposalTimeRangeMaxWidth = def
|
, createProposalTimeRangeMaxWidth = def
|
||||||
|
|
@ -245,7 +244,7 @@ createProposal =
|
||||||
, effects = effects
|
, effects = effects
|
||||||
, status = Draft
|
, status = Draft
|
||||||
, cosigners = [signer]
|
, cosigners = [signer]
|
||||||
, thresholds = defaultProposalThresholds
|
, thresholds = def
|
||||||
, votes = emptyVotesFor effects
|
, votes = emptyVotesFor effects
|
||||||
, timingConfig = def
|
, timingConfig = def
|
||||||
, startingTime = proposalStartingTimeFromTimeRange validTimeRange
|
, startingTime = proposalStartingTimeFromTimeRange validTimeRange
|
||||||
|
|
@ -392,7 +391,7 @@ mintGATs =
|
||||||
governorInputDatum' :: GovernorDatum
|
governorInputDatum' :: GovernorDatum
|
||||||
governorInputDatum' =
|
governorInputDatum' =
|
||||||
GovernorDatum
|
GovernorDatum
|
||||||
{ proposalThresholds = defaultProposalThresholds
|
{ proposalThresholds = def
|
||||||
, nextProposalId = ProposalId 5
|
, nextProposalId = ProposalId 5
|
||||||
, proposalTimings = def
|
, proposalTimings = def
|
||||||
, createProposalTimeRangeMaxWidth = def
|
, createProposalTimeRangeMaxWidth = def
|
||||||
|
|
@ -428,7 +427,7 @@ mintGATs =
|
||||||
, effects = effects
|
, effects = effects
|
||||||
, status = Locked
|
, status = Locked
|
||||||
, cosigners = [signer, signer2]
|
, cosigners = [signer, signer2]
|
||||||
, thresholds = defaultProposalThresholds
|
, thresholds = def
|
||||||
, votes = proposalVotes
|
, votes = proposalVotes
|
||||||
, timingConfig = def
|
, timingConfig = def
|
||||||
, startingTime = ProposalStartingTime 10
|
, startingTime = ProposalStartingTime 10
|
||||||
|
|
@ -587,7 +586,7 @@ mutateState =
|
||||||
governorInputDatum' :: GovernorDatum
|
governorInputDatum' :: GovernorDatum
|
||||||
governorInputDatum' =
|
governorInputDatum' =
|
||||||
GovernorDatum
|
GovernorDatum
|
||||||
{ proposalThresholds = defaultProposalThresholds
|
{ proposalThresholds = def
|
||||||
, nextProposalId = ProposalId 5
|
, nextProposalId = ProposalId 5
|
||||||
, proposalTimings = def
|
, proposalTimings = def
|
||||||
, createProposalTimeRangeMaxWidth = def
|
, createProposalTimeRangeMaxWidth = def
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,12 @@ module Sample.Proposal (
|
||||||
stakeRef,
|
stakeRef,
|
||||||
voteOnProposal,
|
voteOnProposal,
|
||||||
VotingParameters (..),
|
VotingParameters (..),
|
||||||
|
advanceProposalSuccess,
|
||||||
|
advanceProposalFailureTimeout,
|
||||||
|
TransitionParameters (..),
|
||||||
|
advanceFinishedPropsoal,
|
||||||
|
advanceProposalInsufficientVotes,
|
||||||
|
advancePropsoalWithsStake,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
@ -27,6 +33,8 @@ import Plutus.V1.Ledger.Api (
|
||||||
Address (Address),
|
Address (Address),
|
||||||
Credential (ScriptCredential),
|
Credential (ScriptCredential),
|
||||||
Datum (Datum),
|
Datum (Datum),
|
||||||
|
DatumHash,
|
||||||
|
POSIXTime,
|
||||||
POSIXTimeRange,
|
POSIXTimeRange,
|
||||||
PubKeyHash,
|
PubKeyHash,
|
||||||
ScriptContext (..),
|
ScriptContext (..),
|
||||||
|
|
@ -36,6 +44,7 @@ import Plutus.V1.Ledger.Api (
|
||||||
TxInfo (..),
|
TxInfo (..),
|
||||||
TxOut (TxOut, txOutAddress, txOutDatumHash, txOutValue),
|
TxOut (TxOut, txOutAddress, txOutDatumHash, txOutValue),
|
||||||
TxOutRef (TxOutRef),
|
TxOutRef (TxOutRef),
|
||||||
|
ValidatorHash,
|
||||||
)
|
)
|
||||||
import Plutus.V1.Ledger.Value qualified as Value
|
import Plutus.V1.Ledger.Value qualified as Value
|
||||||
import PlutusTx.AssocMap qualified as AssocMap
|
import PlutusTx.AssocMap qualified as AssocMap
|
||||||
|
|
@ -50,6 +59,7 @@ import Agora.Proposal (
|
||||||
ProposalDatum (..),
|
ProposalDatum (..),
|
||||||
ProposalId (..),
|
ProposalId (..),
|
||||||
ProposalStatus (..),
|
ProposalStatus (..),
|
||||||
|
ProposalThresholds (..),
|
||||||
ProposalVotes (..),
|
ProposalVotes (..),
|
||||||
ResultTag (..),
|
ResultTag (..),
|
||||||
emptyVotesFor,
|
emptyVotesFor,
|
||||||
|
|
@ -84,7 +94,7 @@ proposalCreation =
|
||||||
, effects = effects
|
, effects = effects
|
||||||
, status = Draft
|
, status = Draft
|
||||||
, cosigners = [signer]
|
, cosigners = [signer]
|
||||||
, thresholds = defaultProposalThresholds
|
, thresholds = def
|
||||||
, votes = emptyVotesFor effects
|
, votes = emptyVotesFor effects
|
||||||
, timingConfig = def
|
, timingConfig = def
|
||||||
, startingTime = proposalStartingTimeFromTimeRange validTimeRange
|
, startingTime = proposalStartingTimeFromTimeRange validTimeRange
|
||||||
|
|
@ -96,7 +106,7 @@ proposalCreation =
|
||||||
Datum
|
Datum
|
||||||
( toBuiltinData $
|
( toBuiltinData $
|
||||||
GovernorDatum
|
GovernorDatum
|
||||||
{ proposalThresholds = defaultProposalThresholds
|
{ proposalThresholds = def
|
||||||
, nextProposalId = ProposalId 0
|
, nextProposalId = ProposalId 0
|
||||||
, proposalTimings = def
|
, proposalTimings = def
|
||||||
, createProposalTimeRangeMaxWidth = def
|
, createProposalTimeRangeMaxWidth = def
|
||||||
|
|
@ -107,7 +117,7 @@ proposalCreation =
|
||||||
Datum
|
Datum
|
||||||
( toBuiltinData $
|
( toBuiltinData $
|
||||||
GovernorDatum
|
GovernorDatum
|
||||||
{ proposalThresholds = defaultProposalThresholds
|
{ proposalThresholds = def
|
||||||
, nextProposalId = ProposalId 1
|
, nextProposalId = ProposalId 1
|
||||||
, proposalTimings = def
|
, proposalTimings = def
|
||||||
, createProposalTimeRangeMaxWidth = def
|
, createProposalTimeRangeMaxWidth = def
|
||||||
|
|
@ -185,7 +195,7 @@ cosignProposal newSigners =
|
||||||
, effects = effects
|
, effects = effects
|
||||||
, status = Draft
|
, status = Draft
|
||||||
, cosigners = [signer]
|
, cosigners = [signer]
|
||||||
, thresholds = defaultProposalThresholds
|
, thresholds = def
|
||||||
, votes = emptyVotesFor effects
|
, votes = emptyVotesFor effects
|
||||||
, timingConfig = def
|
, timingConfig = def
|
||||||
, startingTime = ProposalStartingTime 0
|
, startingTime = ProposalStartingTime 0
|
||||||
|
|
@ -306,7 +316,7 @@ voteOnProposal params =
|
||||||
, effects = effects
|
, effects = effects
|
||||||
, status = VotingReady
|
, status = VotingReady
|
||||||
, cosigners = [stakeOwner]
|
, cosigners = [stakeOwner]
|
||||||
, thresholds = defaultProposalThresholds
|
, thresholds = def
|
||||||
, votes = ProposalVotes initialVotes
|
, votes = ProposalVotes initialVotes
|
||||||
, timingConfig = def
|
, timingConfig = def
|
||||||
, startingTime = ProposalStartingTime 0
|
, startingTime = ProposalStartingTime 0
|
||||||
|
|
@ -375,7 +385,7 @@ voteOnProposal params =
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
-- Off-chain code should do exactly like this: prepend new lock to the list.
|
-- Off-chain code should do exactly like this: prepend new lock toStatus the list.
|
||||||
updatedLocks :: [ProposalLock]
|
updatedLocks :: [ProposalLock]
|
||||||
updatedLocks = ProposalLock params.voteFor proposalInputDatum'.proposalId : existingLocks
|
updatedLocks = ProposalLock params.voteFor proposalInputDatum'.proposalId : existingLocks
|
||||||
|
|
||||||
|
|
@ -415,3 +425,392 @@ voteOnProposal params =
|
||||||
, txInfoData = datumPair <$> [proposalInputDatum, proposalOutputDatum, stakeInputDatum, stakeOutputDatum]
|
, txInfoData = datumPair <$> [proposalInputDatum, proposalOutputDatum, stakeInputDatum, stakeOutputDatum]
|
||||||
, txInfoId = "827598fb2d69a896bbd9e645bb14c307df907f422b39eecbe4d6329bc30b428c"
|
, txInfoId = "827598fb2d69a896bbd9e645bb14c307df907f422b39eecbe4d6329bc30b428c"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- | Parameters for state transition of proposals.
|
||||||
|
data TransitionParameters = TransitionParameters
|
||||||
|
{ -- The initial status of the propsoal.
|
||||||
|
initialProposalStatus :: ProposalStatus
|
||||||
|
, -- The starting time of the propsoal.
|
||||||
|
proposalStartingTime :: ProposalStartingTime
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Create a 'TxInfo' that update the status of a proposal.
|
||||||
|
mkTransitionTxInfo ::
|
||||||
|
-- | Initial state of the proposal.
|
||||||
|
ProposalStatus ->
|
||||||
|
-- | Next state of the proposal.
|
||||||
|
ProposalStatus ->
|
||||||
|
-- | Effects.
|
||||||
|
AssocMap.Map ResultTag (AssocMap.Map ValidatorHash DatumHash) ->
|
||||||
|
-- | Votes.
|
||||||
|
ProposalVotes ->
|
||||||
|
-- | Starting time of the proposal.
|
||||||
|
ProposalStartingTime ->
|
||||||
|
-- | Valid time range of the transaction.
|
||||||
|
POSIXTimeRange ->
|
||||||
|
TxInfo
|
||||||
|
mkTransitionTxInfo from to effects votes startingTime timeRange =
|
||||||
|
let pst = Value.singleton proposalPolicySymbol "" 1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
proposalInputDatum' :: ProposalDatum
|
||||||
|
proposalInputDatum' =
|
||||||
|
ProposalDatum
|
||||||
|
{ proposalId = ProposalId 0
|
||||||
|
, effects = effects
|
||||||
|
, status = from
|
||||||
|
, cosigners = [signer]
|
||||||
|
, thresholds = def
|
||||||
|
, votes = votes
|
||||||
|
, timingConfig = def
|
||||||
|
, startingTime = startingTime
|
||||||
|
}
|
||||||
|
proposalInputDatum :: Datum
|
||||||
|
proposalInputDatum = Datum $ toBuiltinData proposalInputDatum'
|
||||||
|
proposalInput :: TxOut
|
||||||
|
proposalInput =
|
||||||
|
TxOut
|
||||||
|
{ txOutAddress = proposalValidatorAddress
|
||||||
|
, txOutValue = pst
|
||||||
|
, txOutDatumHash = Just $ toDatumHash proposalInputDatum
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
proposalOutputDatum' :: ProposalDatum
|
||||||
|
proposalOutputDatum' =
|
||||||
|
proposalInputDatum'
|
||||||
|
{ status = to
|
||||||
|
}
|
||||||
|
proposalOutputDatum :: Datum
|
||||||
|
proposalOutputDatum = Datum $ toBuiltinData proposalOutputDatum'
|
||||||
|
proposalOutput :: TxOut
|
||||||
|
proposalOutput =
|
||||||
|
proposalInput
|
||||||
|
{ txOutValue = proposalInput.txOutValue <> minAda
|
||||||
|
, txOutDatumHash = Just $ toDatumHash proposalOutputDatum
|
||||||
|
}
|
||||||
|
in TxInfo
|
||||||
|
{ txInfoInputs = [TxInInfo proposalRef proposalInput]
|
||||||
|
, txInfoOutputs = [proposalOutput]
|
||||||
|
, txInfoFee = Value.singleton "" "" 2
|
||||||
|
, txInfoMint = mempty
|
||||||
|
, txInfoDCert = []
|
||||||
|
, txInfoWdrl = []
|
||||||
|
, txInfoValidRange = timeRange
|
||||||
|
, txInfoSignatories = [signer]
|
||||||
|
, txInfoData = datumPair <$> [proposalInputDatum, proposalOutputDatum]
|
||||||
|
, txInfoId = "95ba4015e30aef16a3461ea97a779f814aeea6b8009d99a94add4b8293be737a"
|
||||||
|
}
|
||||||
|
|
||||||
|
{- | Create a valid 'TxInfo' that advances a proposal, given the parameters.
|
||||||
|
Note that 'TransitionParameters.initialProposalStatus' should not be 'Finished'.
|
||||||
|
-}
|
||||||
|
advanceProposalSuccess :: TransitionParameters -> TxInfo
|
||||||
|
advanceProposalSuccess params =
|
||||||
|
let -- Status of the output proposal.
|
||||||
|
toStatus :: ProposalStatus
|
||||||
|
toStatus = case params.initialProposalStatus of
|
||||||
|
Draft -> VotingReady
|
||||||
|
VotingReady -> Locked
|
||||||
|
Locked -> Finished
|
||||||
|
Finished -> error "Cannot advance 'Finished' proposal"
|
||||||
|
|
||||||
|
effects =
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, AssocMap.empty)
|
||||||
|
, (ResultTag 1, AssocMap.empty)
|
||||||
|
]
|
||||||
|
|
||||||
|
emptyVotes@(ProposalVotes emptyVotes') = emptyVotesFor effects
|
||||||
|
|
||||||
|
-- Set the vote count of outcome 0 to @def.countingVoting + 1@,
|
||||||
|
-- meaning that outcome 0 will be the winner.
|
||||||
|
outcome0WinningVotes =
|
||||||
|
ProposalVotes $
|
||||||
|
updateMap
|
||||||
|
(\_ -> Just $ untag (def :: ProposalThresholds).countVoting + 1)
|
||||||
|
(ResultTag 0)
|
||||||
|
emptyVotes'
|
||||||
|
|
||||||
|
votes :: ProposalVotes
|
||||||
|
votes = case params.initialProposalStatus of
|
||||||
|
Draft -> emptyVotes
|
||||||
|
-- With sufficient votes
|
||||||
|
_ -> outcome0WinningVotes
|
||||||
|
|
||||||
|
proposalStartingTime :: POSIXTime
|
||||||
|
proposalStartingTime =
|
||||||
|
let (ProposalStartingTime startingTime) = params.proposalStartingTime
|
||||||
|
in startingTime
|
||||||
|
|
||||||
|
timeRange :: POSIXTimeRange
|
||||||
|
timeRange = case params.initialProposalStatus of
|
||||||
|
-- [S + 1, S + D - 1]
|
||||||
|
Draft ->
|
||||||
|
closedBoundedInterval
|
||||||
|
(proposalStartingTime + 1)
|
||||||
|
(proposalStartingTime + (def :: ProposalTimingConfig).draftTime - 1)
|
||||||
|
-- [S + D + 1, S + D + V - 1]
|
||||||
|
VotingReady ->
|
||||||
|
closedBoundedInterval
|
||||||
|
( proposalStartingTime
|
||||||
|
+ (def :: ProposalTimingConfig).draftTime
|
||||||
|
+ 1
|
||||||
|
)
|
||||||
|
( proposalStartingTime
|
||||||
|
+ (def :: ProposalTimingConfig).draftTime
|
||||||
|
+ (def :: ProposalTimingConfig).votingTime - 1
|
||||||
|
)
|
||||||
|
-- [S + D + V + L + 1, S + + D + V + L + E - 1]
|
||||||
|
Locked ->
|
||||||
|
closedBoundedInterval
|
||||||
|
( proposalStartingTime
|
||||||
|
+ (def :: ProposalTimingConfig).draftTime
|
||||||
|
+ (def :: ProposalTimingConfig).votingTime
|
||||||
|
+ (def :: ProposalTimingConfig).lockingTime
|
||||||
|
+ 1
|
||||||
|
)
|
||||||
|
( proposalStartingTime
|
||||||
|
+ (def :: ProposalTimingConfig).draftTime
|
||||||
|
+ (def :: ProposalTimingConfig).votingTime
|
||||||
|
+ (def :: ProposalTimingConfig).lockingTime
|
||||||
|
+ (def :: ProposalTimingConfig).executingTime - 1
|
||||||
|
)
|
||||||
|
Finished -> error "Cannot advance 'Finished' proposal"
|
||||||
|
in mkTransitionTxInfo
|
||||||
|
params.initialProposalStatus
|
||||||
|
toStatus
|
||||||
|
effects
|
||||||
|
votes
|
||||||
|
params.proposalStartingTime
|
||||||
|
timeRange
|
||||||
|
|
||||||
|
{- | Create a valid 'TxInfo' that advances a proposal to failed state, given the parameters.
|
||||||
|
The reason why the proposal fails is the proposal has ran out of time.
|
||||||
|
Note that 'TransitionParameters.initialProposalStatus' should not be 'Finished'.
|
||||||
|
-}
|
||||||
|
advanceProposalFailureTimeout :: TransitionParameters -> TxInfo
|
||||||
|
advanceProposalFailureTimeout params =
|
||||||
|
let effects =
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, AssocMap.empty)
|
||||||
|
, (ResultTag 1, AssocMap.empty)
|
||||||
|
]
|
||||||
|
|
||||||
|
emptyVotes@(ProposalVotes emptyVotes') = emptyVotesFor effects
|
||||||
|
|
||||||
|
-- Set the vote count of outcome 0 to @def.countingVoting + 1@,
|
||||||
|
-- meaning that outcome 0 will be the winner.
|
||||||
|
outcome0WinningVotes =
|
||||||
|
ProposalVotes $
|
||||||
|
updateMap
|
||||||
|
(\_ -> Just $ untag (def :: ProposalThresholds).countVoting + 1)
|
||||||
|
(ResultTag 0)
|
||||||
|
emptyVotes'
|
||||||
|
|
||||||
|
votes :: ProposalVotes
|
||||||
|
votes = case params.initialProposalStatus of
|
||||||
|
Draft -> emptyVotes
|
||||||
|
-- With sufficient votes
|
||||||
|
_ -> outcome0WinningVotes
|
||||||
|
|
||||||
|
proposalStartingTime :: POSIXTime
|
||||||
|
proposalStartingTime =
|
||||||
|
let (ProposalStartingTime startingTime) = params.proposalStartingTime
|
||||||
|
in startingTime
|
||||||
|
|
||||||
|
timeRange :: POSIXTimeRange
|
||||||
|
timeRange = case params.initialProposalStatus of
|
||||||
|
-- [S + D + 1, S + D + V - 1]
|
||||||
|
Draft ->
|
||||||
|
closedBoundedInterval
|
||||||
|
(proposalStartingTime + (def :: ProposalTimingConfig).draftTime + 1)
|
||||||
|
( proposalStartingTime
|
||||||
|
+ (def :: ProposalTimingConfig).draftTime
|
||||||
|
+ (def :: ProposalTimingConfig).votingTime - 1
|
||||||
|
)
|
||||||
|
-- [S + D + V + 1, S + D + V + L -1]
|
||||||
|
VotingReady ->
|
||||||
|
closedBoundedInterval
|
||||||
|
( proposalStartingTime
|
||||||
|
+ (def :: ProposalTimingConfig).draftTime
|
||||||
|
+ (def :: ProposalTimingConfig).votingTime
|
||||||
|
+ 1
|
||||||
|
)
|
||||||
|
( proposalStartingTime
|
||||||
|
+ (def :: ProposalTimingConfig).draftTime
|
||||||
|
+ (def :: ProposalTimingConfig).votingTime
|
||||||
|
+ (def :: ProposalTimingConfig).lockingTime - 1
|
||||||
|
)
|
||||||
|
-- [S + D + V + L + E + 1, S + D + V + L + E + 100]
|
||||||
|
Locked ->
|
||||||
|
closedBoundedInterval
|
||||||
|
( proposalStartingTime
|
||||||
|
+ (def :: ProposalTimingConfig).draftTime
|
||||||
|
+ (def :: ProposalTimingConfig).votingTime
|
||||||
|
+ (def :: ProposalTimingConfig).lockingTime
|
||||||
|
+ (def :: ProposalTimingConfig).executingTime
|
||||||
|
+ 1
|
||||||
|
)
|
||||||
|
( proposalStartingTime
|
||||||
|
+ (def :: ProposalTimingConfig).draftTime
|
||||||
|
+ (def :: ProposalTimingConfig).votingTime
|
||||||
|
+ (def :: ProposalTimingConfig).lockingTime
|
||||||
|
+ (def :: ProposalTimingConfig).executingTime
|
||||||
|
+ 100
|
||||||
|
)
|
||||||
|
Finished -> error "Cannot advance 'Finished' proposal"
|
||||||
|
in mkTransitionTxInfo
|
||||||
|
params.initialProposalStatus
|
||||||
|
Finished
|
||||||
|
effects
|
||||||
|
votes
|
||||||
|
params.proposalStartingTime
|
||||||
|
timeRange
|
||||||
|
|
||||||
|
-- | An invalid 'TxInfo' that tries to advance a 'VotingReady' proposal without sufficient votes.
|
||||||
|
advanceProposalInsufficientVotes :: TxInfo
|
||||||
|
advanceProposalInsufficientVotes =
|
||||||
|
let effects =
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, AssocMap.empty)
|
||||||
|
, (ResultTag 1, AssocMap.empty)
|
||||||
|
]
|
||||||
|
|
||||||
|
-- Insufficient votes.
|
||||||
|
votes = emptyVotesFor effects
|
||||||
|
|
||||||
|
proposalStartingTime = 0
|
||||||
|
|
||||||
|
-- Valid time range.
|
||||||
|
-- [S + D + 1, S + V - 1]
|
||||||
|
timeRange =
|
||||||
|
closedBoundedInterval
|
||||||
|
(proposalStartingTime + (def :: ProposalTimingConfig).draftTime + 1)
|
||||||
|
(proposalStartingTime + (def :: ProposalTimingConfig).votingTime - 1)
|
||||||
|
in mkTransitionTxInfo
|
||||||
|
VotingReady
|
||||||
|
Locked
|
||||||
|
effects
|
||||||
|
votes
|
||||||
|
(ProposalStartingTime proposalStartingTime)
|
||||||
|
timeRange
|
||||||
|
|
||||||
|
-- | An invalid 'TxInfo' that tries to advance a 'Finished' proposal.
|
||||||
|
advanceFinishedPropsoal :: TxInfo
|
||||||
|
advanceFinishedPropsoal =
|
||||||
|
let effects =
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, AssocMap.empty)
|
||||||
|
, (ResultTag 1, AssocMap.empty)
|
||||||
|
]
|
||||||
|
|
||||||
|
-- Set the vote count of outcome 0 to @def.countingVoting + 1@,
|
||||||
|
-- meaning that outcome 0 will be the winner.
|
||||||
|
outcome0WinningVotes =
|
||||||
|
ProposalVotes $
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, untag (def :: ProposalThresholds).countVoting + 1)
|
||||||
|
, (ResultTag 1, 0)
|
||||||
|
]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
timeRange =
|
||||||
|
closedBoundedInterval
|
||||||
|
((def :: ProposalTimingConfig).lockingTime + 1)
|
||||||
|
((def :: ProposalTimingConfig).executingTime - 1)
|
||||||
|
in mkTransitionTxInfo
|
||||||
|
Finished
|
||||||
|
Finished
|
||||||
|
effects
|
||||||
|
outcome0WinningVotes
|
||||||
|
(ProposalStartingTime 0)
|
||||||
|
timeRange
|
||||||
|
|
||||||
|
{- | An illegal 'TxInfo' that tries to use 'AdvanceProposal' with a stake.
|
||||||
|
From the perspective of stake validator, the transition is valid,
|
||||||
|
so the proposal validator should reject this.
|
||||||
|
-}
|
||||||
|
advancePropsoalWithsStake :: TxInfo
|
||||||
|
advancePropsoalWithsStake =
|
||||||
|
let templateTxInfo =
|
||||||
|
advanceProposalSuccess
|
||||||
|
TransitionParameters
|
||||||
|
{ initialProposalStatus = VotingReady
|
||||||
|
, proposalStartingTime = ProposalStartingTime 0
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Now we create a new lock on an arbitrary stake
|
||||||
|
|
||||||
|
sst = Value.assetClassValue stakeAssetClass 1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
stakeOwner = signer
|
||||||
|
stakedAmount = 200
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
existingLocks :: [ProposalLock]
|
||||||
|
existingLocks =
|
||||||
|
[ ProposalLock (ResultTag 0) (ProposalId 0)
|
||||||
|
, ProposalLock (ResultTag 2) (ProposalId 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
stakeInputDatum' :: StakeDatum
|
||||||
|
stakeInputDatum' =
|
||||||
|
StakeDatum
|
||||||
|
{ stakedAmount = Tagged stakedAmount
|
||||||
|
, owner = stakeOwner
|
||||||
|
, lockedBy = existingLocks
|
||||||
|
}
|
||||||
|
stakeInputDatum :: Datum
|
||||||
|
stakeInputDatum = Datum $ toBuiltinData stakeInputDatum'
|
||||||
|
stakeInput :: TxOut
|
||||||
|
stakeInput =
|
||||||
|
TxOut
|
||||||
|
{ txOutAddress = stakeAddress
|
||||||
|
, txOutValue =
|
||||||
|
mconcat
|
||||||
|
[ sst
|
||||||
|
, Value.assetClassValue (untag stake.gtClassRef) stakedAmount
|
||||||
|
, minAda
|
||||||
|
]
|
||||||
|
, txOutDatumHash = Just $ toDatumHash stakeInputDatum
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
updatedLocks :: [ProposalLock]
|
||||||
|
updatedLocks = ProposalLock (ResultTag 42) (ProposalId 27) : existingLocks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
stakeOutputDatum' :: StakeDatum
|
||||||
|
stakeOutputDatum' =
|
||||||
|
stakeInputDatum'
|
||||||
|
{ lockedBy = updatedLocks
|
||||||
|
}
|
||||||
|
stakeOutputDatum :: Datum
|
||||||
|
stakeOutputDatum = Datum $ toBuiltinData stakeOutputDatum'
|
||||||
|
stakeOutput :: TxOut
|
||||||
|
stakeOutput =
|
||||||
|
stakeInput
|
||||||
|
{ txOutDatumHash = Just $ toDatumHash stakeOutputDatum
|
||||||
|
}
|
||||||
|
in templateTxInfo
|
||||||
|
{ txInfoInputs = TxInInfo stakeRef stakeInput : templateTxInfo.txInfoInputs
|
||||||
|
, txInfoOutputs = stakeOutput : templateTxInfo.txInfoOutputs
|
||||||
|
, txInfoData =
|
||||||
|
(datumPair <$> [stakeInputDatum, stakeOutputDatum])
|
||||||
|
<> templateTxInfo.txInfoData
|
||||||
|
, txInfoSignatories = [stakeOwner]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ module Sample.Shared (
|
||||||
gstUTXORef,
|
gstUTXORef,
|
||||||
|
|
||||||
-- ** Proposal
|
-- ** Proposal
|
||||||
defaultProposalThresholds,
|
|
||||||
proposal,
|
proposal,
|
||||||
proposalPolicySymbol,
|
proposalPolicySymbol,
|
||||||
proposalValidatorHash,
|
proposalValidatorHash,
|
||||||
|
|
@ -184,13 +183,16 @@ proposalValidatorHash = proposalValidatorHashFromGovernor governor
|
||||||
proposalValidatorAddress :: Address
|
proposalValidatorAddress :: Address
|
||||||
proposalValidatorAddress = scriptHashAddress proposalValidatorHash
|
proposalValidatorAddress = scriptHashAddress proposalValidatorHash
|
||||||
|
|
||||||
defaultProposalThresholds :: ProposalThresholds
|
{- | Default value of 'Agora.Proposal.ProposalThresholds'.
|
||||||
defaultProposalThresholds =
|
For testing purpose only.
|
||||||
ProposalThresholds
|
-}
|
||||||
{ countVoting = Tagged 1000
|
instance Default ProposalThresholds where
|
||||||
, create = Tagged 1
|
def =
|
||||||
, startVoting = Tagged 10
|
ProposalThresholds
|
||||||
}
|
{ countVoting = Tagged 1000
|
||||||
|
, create = Tagged 1
|
||||||
|
, startVoting = Tagged 10
|
||||||
|
}
|
||||||
|
|
||||||
authorityToken :: AuthorityToken
|
authorityToken :: AuthorityToken
|
||||||
authorityToken = authorityTokenFromGovernor governor
|
authorityToken = authorityTokenFromGovernor governor
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ specs =
|
||||||
"governor validator should pass"
|
"governor validator should pass"
|
||||||
(governorValidator Shared.governor)
|
(governorValidator Shared.governor)
|
||||||
( GovernorDatum
|
( GovernorDatum
|
||||||
Shared.defaultProposalThresholds
|
def
|
||||||
(ProposalId 0)
|
(ProposalId 0)
|
||||||
def
|
def
|
||||||
def
|
def
|
||||||
|
|
@ -56,7 +56,7 @@ specs =
|
||||||
"governor validator should fail"
|
"governor validator should fail"
|
||||||
(governorValidator Shared.governor)
|
(governorValidator Shared.governor)
|
||||||
( GovernorDatum
|
( GovernorDatum
|
||||||
Shared.defaultProposalThresholds
|
def
|
||||||
(ProposalId 0)
|
(ProposalId 0)
|
||||||
def
|
def
|
||||||
def
|
def
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ specs =
|
||||||
"proposal creation"
|
"proposal creation"
|
||||||
(governorValidator Shared.governor)
|
(governorValidator Shared.governor)
|
||||||
( GovernorDatum
|
( GovernorDatum
|
||||||
Shared.defaultProposalThresholds
|
def
|
||||||
(ProposalId 0)
|
(ProposalId 0)
|
||||||
def
|
def
|
||||||
def
|
def
|
||||||
|
|
@ -55,7 +55,7 @@ specs =
|
||||||
"GATs minting"
|
"GATs minting"
|
||||||
(governorValidator Shared.governor)
|
(governorValidator Shared.governor)
|
||||||
( GovernorDatum
|
( GovernorDatum
|
||||||
Shared.defaultProposalThresholds
|
def
|
||||||
(ProposalId 5)
|
(ProposalId 5)
|
||||||
def
|
def
|
||||||
def
|
def
|
||||||
|
|
@ -66,7 +66,7 @@ specs =
|
||||||
"mutate governor state"
|
"mutate governor state"
|
||||||
(governorValidator Shared.governor)
|
(governorValidator Shared.governor)
|
||||||
( GovernorDatum
|
( GovernorDatum
|
||||||
Shared.defaultProposalThresholds
|
def
|
||||||
(ProposalId 5)
|
(ProposalId 5)
|
||||||
def
|
def
|
||||||
def
|
def
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,9 @@ import Agora.Proposal (
|
||||||
Proposal (..),
|
Proposal (..),
|
||||||
ProposalDatum (..),
|
ProposalDatum (..),
|
||||||
ProposalId (ProposalId),
|
ProposalId (ProposalId),
|
||||||
ProposalRedeemer (Cosign, Vote),
|
ProposalRedeemer (..),
|
||||||
ProposalStatus (Draft, VotingReady),
|
ProposalStatus (..),
|
||||||
|
ProposalThresholds (..),
|
||||||
ProposalVotes (ProposalVotes),
|
ProposalVotes (ProposalVotes),
|
||||||
ResultTag (ResultTag),
|
ResultTag (ResultTag),
|
||||||
cosigners,
|
cosigners,
|
||||||
|
|
@ -39,7 +40,7 @@ import Agora.Stake (
|
||||||
)
|
)
|
||||||
import Agora.Stake.Scripts (stakeValidator)
|
import Agora.Stake.Scripts (stakeValidator)
|
||||||
import Data.Default.Class (Default (def))
|
import Data.Default.Class (Default (def))
|
||||||
import Data.Tagged (Tagged (Tagged))
|
import Data.Tagged (Tagged (Tagged), untag)
|
||||||
import Plutus.V1.Ledger.Api (ScriptContext (..), ScriptPurpose (..))
|
import Plutus.V1.Ledger.Api (ScriptContext (..), ScriptPurpose (..))
|
||||||
import PlutusTx.AssocMap qualified as AssocMap
|
import PlutusTx.AssocMap qualified as AssocMap
|
||||||
import Sample.Proposal qualified as Proposal
|
import Sample.Proposal qualified as Proposal
|
||||||
|
|
@ -49,6 +50,7 @@ import Spec.Specification (
|
||||||
SpecificationTree,
|
SpecificationTree,
|
||||||
group,
|
group,
|
||||||
policySucceedsWith,
|
policySucceedsWith,
|
||||||
|
validatorFailsWith,
|
||||||
validatorSucceedsWith,
|
validatorSucceedsWith,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -81,7 +83,7 @@ specs =
|
||||||
]
|
]
|
||||||
, status = Draft
|
, status = Draft
|
||||||
, cosigners = [signer]
|
, cosigners = [signer]
|
||||||
, thresholds = Shared.defaultProposalThresholds
|
, thresholds = def
|
||||||
, votes =
|
, votes =
|
||||||
emptyVotesFor $
|
emptyVotesFor $
|
||||||
AssocMap.fromList
|
AssocMap.fromList
|
||||||
|
|
@ -115,7 +117,7 @@ specs =
|
||||||
]
|
]
|
||||||
, status = VotingReady
|
, status = VotingReady
|
||||||
, cosigners = [signer]
|
, cosigners = [signer]
|
||||||
, thresholds = Shared.defaultProposalThresholds
|
, thresholds = def
|
||||||
, votes =
|
, votes =
|
||||||
ProposalVotes
|
ProposalVotes
|
||||||
( AssocMap.fromList
|
( AssocMap.fromList
|
||||||
|
|
@ -158,5 +160,189 @@ specs =
|
||||||
(Spending Proposal.stakeRef)
|
(Spending Proposal.stakeRef)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
, group
|
||||||
|
"advancing"
|
||||||
|
[ group "successfully advance to next state" $
|
||||||
|
map
|
||||||
|
( \(name, initialState) ->
|
||||||
|
validatorSucceedsWith
|
||||||
|
name
|
||||||
|
(proposalValidator Shared.proposal)
|
||||||
|
( ProposalDatum
|
||||||
|
{ proposalId = ProposalId 0
|
||||||
|
, effects =
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, AssocMap.empty)
|
||||||
|
, (ResultTag 1, AssocMap.empty)
|
||||||
|
]
|
||||||
|
, status = initialState
|
||||||
|
, cosigners = [signer]
|
||||||
|
, thresholds = def
|
||||||
|
, votes =
|
||||||
|
ProposalVotes
|
||||||
|
( AssocMap.fromList
|
||||||
|
[
|
||||||
|
( ResultTag 0
|
||||||
|
, case initialState of
|
||||||
|
Draft -> 0
|
||||||
|
_ -> untag (def :: ProposalThresholds).countVoting + 1
|
||||||
|
)
|
||||||
|
, (ResultTag 1, 0)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
, timingConfig = def
|
||||||
|
, startingTime = ProposalStartingTime 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
AdvanceProposal
|
||||||
|
( ScriptContext
|
||||||
|
( Proposal.advanceProposalSuccess
|
||||||
|
Proposal.TransitionParameters
|
||||||
|
{ Proposal.initialProposalStatus = initialState
|
||||||
|
, Proposal.proposalStartingTime = ProposalStartingTime 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
(Spending Proposal.proposalRef)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
[ ("Draft -> VotringReady", Draft)
|
||||||
|
, ("VotingReady -> Locked", VotingReady)
|
||||||
|
, ("Locked -> Finished", Locked)
|
||||||
|
]
|
||||||
|
, group "successfully advance to failed state: timeout" $
|
||||||
|
map
|
||||||
|
( \(name, initialState) ->
|
||||||
|
validatorSucceedsWith
|
||||||
|
name
|
||||||
|
(proposalValidator Shared.proposal)
|
||||||
|
( ProposalDatum
|
||||||
|
{ proposalId = ProposalId 0
|
||||||
|
, effects =
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, AssocMap.empty)
|
||||||
|
, (ResultTag 1, AssocMap.empty)
|
||||||
|
]
|
||||||
|
, status = initialState
|
||||||
|
, cosigners = [signer]
|
||||||
|
, thresholds = def
|
||||||
|
, votes =
|
||||||
|
ProposalVotes
|
||||||
|
( AssocMap.fromList
|
||||||
|
[
|
||||||
|
( ResultTag 0
|
||||||
|
, case initialState of
|
||||||
|
Draft -> 0
|
||||||
|
_ -> untag (def :: ProposalThresholds).countVoting + 1
|
||||||
|
)
|
||||||
|
, (ResultTag 1, 0)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
, timingConfig = def
|
||||||
|
, startingTime = ProposalStartingTime 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
AdvanceProposal
|
||||||
|
( ScriptContext
|
||||||
|
( Proposal.advanceProposalFailureTimeout
|
||||||
|
Proposal.TransitionParameters
|
||||||
|
{ Proposal.initialProposalStatus = initialState
|
||||||
|
, Proposal.proposalStartingTime = ProposalStartingTime 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
(Spending Proposal.proposalRef)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
[ ("Draft -> Finished", Draft)
|
||||||
|
, ("VotingReady -> Finished", VotingReady)
|
||||||
|
, ("Locked -> Finished", Locked)
|
||||||
|
]
|
||||||
|
, validatorFailsWith
|
||||||
|
"illegal: insufficient votes"
|
||||||
|
(proposalValidator Shared.proposal)
|
||||||
|
( ProposalDatum
|
||||||
|
{ proposalId = ProposalId 0
|
||||||
|
, effects =
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, AssocMap.empty)
|
||||||
|
, (ResultTag 1, AssocMap.empty)
|
||||||
|
]
|
||||||
|
, status = VotingReady
|
||||||
|
, cosigners = [signer]
|
||||||
|
, thresholds = def
|
||||||
|
, votes =
|
||||||
|
ProposalVotes
|
||||||
|
( AssocMap.fromList
|
||||||
|
[ (ResultTag 0, 0)
|
||||||
|
, (ResultTag 1, 0)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
, timingConfig = def
|
||||||
|
, startingTime = ProposalStartingTime 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
AdvanceProposal
|
||||||
|
( ScriptContext
|
||||||
|
Proposal.advanceProposalInsufficientVotes
|
||||||
|
(Spending Proposal.proposalRef)
|
||||||
|
)
|
||||||
|
, validatorFailsWith
|
||||||
|
"illegal: initial state is Finished"
|
||||||
|
(proposalValidator Shared.proposal)
|
||||||
|
( ProposalDatum
|
||||||
|
{ proposalId = ProposalId 0
|
||||||
|
, effects =
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, AssocMap.empty)
|
||||||
|
, (ResultTag 1, AssocMap.empty)
|
||||||
|
]
|
||||||
|
, status = Finished
|
||||||
|
, cosigners = [signer]
|
||||||
|
, thresholds = def
|
||||||
|
, votes =
|
||||||
|
ProposalVotes
|
||||||
|
( AssocMap.fromList
|
||||||
|
[ (ResultTag 0, untag (def :: ProposalThresholds).countVoting + 1)
|
||||||
|
, (ResultTag 1, 0)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
, timingConfig = def
|
||||||
|
, startingTime = ProposalStartingTime 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
AdvanceProposal
|
||||||
|
( ScriptContext
|
||||||
|
Proposal.advanceFinishedPropsoal
|
||||||
|
(Spending Proposal.proposalRef)
|
||||||
|
)
|
||||||
|
, validatorFailsWith
|
||||||
|
"illegal: with stake input"
|
||||||
|
(proposalValidator Shared.proposal)
|
||||||
|
( ProposalDatum
|
||||||
|
{ proposalId = ProposalId 0
|
||||||
|
, effects =
|
||||||
|
AssocMap.fromList
|
||||||
|
[ (ResultTag 0, AssocMap.empty)
|
||||||
|
, (ResultTag 1, AssocMap.empty)
|
||||||
|
]
|
||||||
|
, status = VotingReady
|
||||||
|
, cosigners = [signer]
|
||||||
|
, thresholds = def
|
||||||
|
, votes =
|
||||||
|
ProposalVotes
|
||||||
|
( AssocMap.fromList
|
||||||
|
[ (ResultTag 0, 0)
|
||||||
|
, (ResultTag 1, 0)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
, timingConfig = def
|
||||||
|
, startingTime = ProposalStartingTime 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
AdvanceProposal
|
||||||
|
( ScriptContext
|
||||||
|
Proposal.advancePropsoalWithsStake
|
||||||
|
(Spending Proposal.proposalRef)
|
||||||
|
)
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,12 @@ Agora/Proposal/validator/cosignature/proposal,241651391,511819,5772
|
||||||
Agora/Proposal/validator/cosignature/stake,186332635,402961,4561
|
Agora/Proposal/validator/cosignature/stake,186332635,402961,4561
|
||||||
Agora/Proposal/validator/voting/proposal,240181636,491168,5780
|
Agora/Proposal/validator/voting/proposal,240181636,491168,5780
|
||||||
Agora/Proposal/validator/voting/stake,154223940,328703,4614
|
Agora/Proposal/validator/voting/stake,154223940,328703,4614
|
||||||
|
Agora/Proposal/validator/advancing/successfully advance to next state/Draft -> VotringReady,129146959,254742,5158
|
||||||
|
Agora/Proposal/validator/advancing/successfully advance to next state/VotingReady -> Locked,138455315,275396,5166
|
||||||
|
Agora/Proposal/validator/advancing/successfully advance to next state/Locked -> Finished,131138537,260050,5167
|
||||||
|
Agora/Proposal/validator/advancing/successfully advance to failed state: timeout/Draft -> Finished,127634992,252012,5160
|
||||||
|
Agora/Proposal/validator/advancing/successfully advance to failed state: timeout/VotingReady -> Finished,128625282,254416,5167
|
||||||
|
Agora/Proposal/validator/advancing/successfully advance to failed state: timeout/Locked -> Finished,128130137,253214,5167
|
||||||
Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple,25177457,55883,806
|
Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple,25177457,55883,806
|
||||||
Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs,40266637,88241,900
|
Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs,40266637,88241,900
|
||||||
Agora/Treasury/Validator/Positive/Allows for effect changes,37343572,79744,1841
|
Agora/Treasury/Validator/Positive/Allows for effect changes,37343572,79744,1841
|
||||||
|
|
|
||||||
|
Loading…
Add table
Add a link
Reference in a new issue