Merge pull request #52 from Liqwid-Labs/emiflake/docs
Various documentation additions
This commit is contained in:
commit
ce8f6365bc
7 changed files with 102 additions and 36 deletions
|
|
@ -18,7 +18,7 @@ module Agora.Governor (
|
|||
governorValidator,
|
||||
) where
|
||||
|
||||
import Agora.Proposal (ProposalTag, ProposalThresholds)
|
||||
import Agora.Proposal (ProposalId, ProposalThresholds)
|
||||
import Plutarch (popaque)
|
||||
import Plutarch.Api.V1 (PMintingPolicy, PValidator)
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ import Plutarch.Api.V1 (PMintingPolicy, PValidator)
|
|||
data GovernorDatum = GovernorDatum
|
||||
{ proposalThresholds :: ProposalThresholds
|
||||
-- ^ Gets copied over upon creation of a 'Agora.Proposal.ProposalDatum'.
|
||||
, nextProposalTag :: ProposalTag
|
||||
, nextProposalId :: ProposalId
|
||||
-- ^ What tag the next proposal will get upon creating.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module Agora.Proposal (
|
|||
ProposalStatus (..),
|
||||
ProposalThresholds (..),
|
||||
ProposalVotes (..),
|
||||
ProposalTag (..),
|
||||
ProposalId (..),
|
||||
ResultTag (..),
|
||||
|
||||
-- * Plutarch-land
|
||||
|
|
@ -22,7 +22,7 @@ module Agora.Proposal (
|
|||
PProposalStatus (..),
|
||||
PProposalThresholds (..),
|
||||
PProposalVotes (..),
|
||||
PProposalTag (..),
|
||||
PProposalId (..),
|
||||
PResultTag (..),
|
||||
|
||||
-- * Scripts
|
||||
|
|
@ -143,7 +143,7 @@ data ProposalDatum = ProposalDatum
|
|||
{ -- TODO: could we encode this more efficiently?
|
||||
-- This is shaped this way for future proofing.
|
||||
-- See https://github.com/Liqwid-Labs/agora/issues/39
|
||||
effects :: [(ResultTag, [(ValidatorHash, DatumHash)])]
|
||||
effects :: AssocMap.Map ResultTag [(ValidatorHash, DatumHash)]
|
||||
-- ^ Effect lookup table. First by result, then by effect hash.
|
||||
, status :: ProposalStatus
|
||||
-- ^ The status the proposal is in.
|
||||
|
|
@ -160,10 +160,10 @@ PlutusTx.makeIsDataIndexed ''ProposalDatum [('ProposalDatum, 0)]
|
|||
|
||||
{- | Identifies a Proposal, issued upon creation of a proposal.
|
||||
In practice, this number starts at zero, and increments by one
|
||||
for each proposal. The 100th proposal will be @'ProposalTag' 99@.
|
||||
This counter lives in the 'Governor', see 'nextProposalTag'.
|
||||
for each proposal. The 100th proposal will be @'ProposalId' 99@.
|
||||
This counter lives in the 'Governor', see 'nextProposalId'.
|
||||
-}
|
||||
newtype ProposalTag = ProposalTag {proposalTag :: Integer}
|
||||
newtype ProposalId = ProposalId {proposalTag :: Integer}
|
||||
deriving newtype (PlutusTx.ToData, PlutusTx.FromData, PlutusTx.UnsafeFromData)
|
||||
deriving stock (Eq, Show, GHC.Generic)
|
||||
|
||||
|
|
@ -183,15 +183,15 @@ deriving via
|
|||
instance
|
||||
(PConstant ResultTag)
|
||||
|
||||
-- | Plutarch-level version of 'PProposalTag'.
|
||||
newtype PProposalTag (s :: S) = PProposalTag (Term s PInteger)
|
||||
deriving (PlutusType, PIsData, PEq, POrd) via (DerivePNewtype PProposalTag PInteger)
|
||||
-- | Plutarch-level version of 'PProposalId'.
|
||||
newtype PProposalId (s :: S) = PProposalId (Term s PInteger)
|
||||
deriving (PlutusType, PIsData, PEq, POrd) via (DerivePNewtype PProposalId PInteger)
|
||||
|
||||
instance PUnsafeLiftDecl PProposalTag where type PLifted PProposalTag = ProposalTag
|
||||
instance PUnsafeLiftDecl PProposalId where type PLifted PProposalId = ProposalId
|
||||
deriving via
|
||||
(DerivePConstantViaNewtype ProposalTag PProposalTag PInteger)
|
||||
(DerivePConstantViaNewtype ProposalId PProposalId PInteger)
|
||||
instance
|
||||
(PConstant ProposalTag)
|
||||
(PConstant ProposalId)
|
||||
|
||||
-- | Plutarch-level version of 'ProposalStatus'.
|
||||
data PProposalStatus (s :: S)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ import Plutus.V1.Ledger.Value (AssetClass (AssetClass))
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
import Agora.Proposal (PProposalTag, PResultTag, ProposalTag (..), ResultTag (..))
|
||||
import Agora.Proposal (PProposalId, PResultTag, ProposalId (..), ResultTag (..))
|
||||
import Agora.SafeMoney (GTTag)
|
||||
import Agora.Utils (
|
||||
anyInput,
|
||||
|
|
@ -119,8 +119,8 @@ data ProposalLock = ProposalLock
|
|||
{ vote :: ResultTag
|
||||
-- ^ What was voted on. This allows retracting votes to
|
||||
-- undo their vote.
|
||||
, proposalTag :: ProposalTag
|
||||
-- ^ Identifies the proposal. See 'ProposalTag' for further
|
||||
, proposalId :: ProposalId
|
||||
-- ^ Identifies the proposal. See 'ProposalId' for further
|
||||
-- comments on its significance.
|
||||
}
|
||||
deriving stock (Show, GHC.Generic)
|
||||
|
|
@ -222,7 +222,7 @@ newtype PProposalLock (s :: S) = PProposalLock
|
|||
s
|
||||
( PDataRecord
|
||||
'[ "vote" ':= PResultTag
|
||||
, "proposalTag" ':= PProposalTag
|
||||
, "proposalTag" ':= PProposalId
|
||||
]
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
| Specification | Implementation | Last revision |
|
||||
|:-----------:|:--------------:|:-------------:|
|
||||
| WIP | WIP | v0.1 2022-02-03 |
|
||||
| WIP | WIP | v0.1 2022-04-11 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -32,12 +32,14 @@ We don't. Effects will be _unable_ to alter the system without burning [_governa
|
|||
|
||||
All 'governable' components of a system must be able to interface with effects and allow them to make necessary changes, so long as they are in possession of a GAT.
|
||||
|
||||
In order for effects to be identifiable through some off-chain metadata and verification of source code, it helps for effects to be reusable, their varied functionality being dependent on their datum. This allows for effects to be given names, be audited, and to be tracked. The datums are more easily inspected because of human-readable representations of their underlying encoding in [CBOR](https://en.wikipedia.org/wiki/CBOR) (See [`plutus_data` in alonzo.cddl](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/alonzo/test-suite/cddl-files/alonzo.cddl#L274-L279))
|
||||
|
||||
## What can an effect _be_?
|
||||
|
||||
The range of powers an effect may have is at the discretion of the protocol maker. For usability purposes, Agora might offer a _buffet approach_ as an option for proposals and effects.
|
||||
|
||||
<p align="center">
|
||||
<img height=300 src="https://images.unsplash.com/photo-1583338917496-7ea264c374ce?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80" alt="Get the effects, whilst they're hot!"/>
|
||||
<img height=300 src="https://images.unsplash.com/photo-1583338917496-7ea264c374ce?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80" alt="Get the effects, whilst they're hot!"/>
|
||||
</p>
|
||||
|
||||
In this model, a proposal is defined by the _combination_ of _effect templates_, in much the same way a diner's meal at a buffet is defined by which dishes they choose.
|
||||
|
|
@ -51,3 +53,9 @@ Whilst Agora may offer this functionality, there is nothing stopping DAO members
|
|||
An anticipated problem with this model is the danger of 'partial execution'. The model relies on the assumption that desired effects will be processed by community members, as they are seen as desirable.There could however be an issue, if users deem some effects as more desirable than others. If the effects of a proposal are not executed **in their entirety**, this may lead to unanticipated and undesirable outcomes.
|
||||
|
||||
This should not be a major limitation in the system, as community members _should_ recognise the necessity to implement the proposal in its entirety. However, one might consider _incentivising effect execution_ to prevent such an occurrence.
|
||||
|
||||
## Guidelines for building effects
|
||||
|
||||
The primary safety consideration for handling GATs with proposal effects should be that an effect's transaction should only be valid when it burns exactly one GAT. This essentially prevents all of the issues of authority token leaking, multi-GAT burn issues, etc.
|
||||
|
||||
Furthermore, an effect could require that no funds are sent to the effect within the spend transaction. This prevents issues with residue datums leaking into future uses of the same script (reuse of scripts is a *requirement* for correct tagging, implementation safety, etc).
|
||||
|
|
|
|||
|
|
@ -11,15 +11,34 @@
|
|||
**Authors**:
|
||||
|
||||
- [Jack Hodgkinson]
|
||||
- [Emily Martins]
|
||||
|
||||
**Implementation ownership:** _unassigned_
|
||||
|
||||
[Jack Hodgkinson]: https://github.com/jhodgdev
|
||||
|
||||
[Emily Martins]: https://github.com/emiflake
|
||||
|
||||
**Current Status**:
|
||||
|
||||
First draft. Subject to review by @emiflake.
|
||||
First draft.
|
||||
|
||||
---
|
||||
|
||||
The governor is a simpler component than others in the system but still provides an invaluable role. Firstly, it acts as a repository for all the governance parameters e.g. the duration of proposal phases or GT thresholds. Secondly, and perhaps most importantly, it verifies whether proposals have passed legally and, if they have, grants their [effects](effects.md) powerful [governance authority tokens](authority-tokens.md).
|
||||
The governor is a simpler component than others in the system but still provides an invaluable role.
|
||||
|
||||
### Governor responsibilities
|
||||
|
||||
The governor acts as the central authority through which all governance proceeds indirectly. You can think of it as the single point for issuing rights to actors.
|
||||
|
||||
#### Minting of authority tokens
|
||||
|
||||
The main responsibility for the governor is allowing the minting of [authority tokens](authority-tokens.md), and ensuring they are sent to [effects](effects.md). The governor needs to check that this happens as a result of a proposal finishing its voting phase.
|
||||
|
||||
#### Guarding creation of proposals
|
||||
|
||||
The governor is also responsible for allowing the _creation_ of proposals. There are a few rules for the creation of a proposal, and the governor ensures these rules are followed.
|
||||
|
||||
In order for proposals to have sequential IDs, the governor keeps track of a counter which it uses to ensure an ID has not been taken yet. The governor also needs to keep global settings that influence how proposals behave: thresholds for state transitions, how long each phase lasts, etc.
|
||||
|
||||
The governor, in-line with other Agora components, allows its state to be mutated, subject to the burning of an authority token.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This document gives an overview of the technical design of the proposals system
|
|||
|
||||
| Specification | Implementation | Last revision |
|
||||
|:-----------:|:-----------:|:-------------:|
|
||||
| WIP | WIP | v0.1 2022-02-02 |
|
||||
| WIP | WIP | v0.1 2022-04-11 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -49,25 +49,21 @@ Consider the following 'stages' of a proposal:
|
|||
- `L`: the length of the locking period.
|
||||
- `E`: the length of the execution period.
|
||||
|
||||
| Action | Valid POSIXTimeRange | Valid _stored_ state(s) |
|
||||
|-------------------------------------|------------------------------------|-------------------------|
|
||||
| Witness | \[S, ∞) | \* |
|
||||
| Action | Valid POSIXTimeRange | Valid _stored_ state(s) |
|
||||
|-------------------------------------|-------------------------------------|-------------------------|
|
||||
| Witness | \[S, ∞) | \* |
|
||||
| Cosign | \[S, S + D) | Draft |
|
||||
| AdvanceProposal | \[S, S + D) | Draft |
|
||||
| Vote | \[S + D, S + D + V) | Voting |
|
||||
| Unlock | \[S + D, ∞) | \* |
|
||||
| CountVotes (? see spec comment) | \[S + D + V, S + D + V + L) | Voting |
|
||||
| Unlock | \[S + D, ∞) | \* |
|
||||
| CountVotes | \[S + D + V, S + D + V + L) | Voting |
|
||||
| ExecuteProposal (if quorum reached) | \[S + D + V + L, S + D + V + L + E) | Voting |
|
||||
|
||||
```diff
|
||||
- CountVotes takes a snapshot after voting has ended, it allows users to unlock their stake without affecting votes, after the lock period has ended. This is an optional feature of locking, do we want this?
|
||||
```
|
||||
|
||||
> Jack 2022-02-02: I will consider revising this table further at a later time.
|
||||
|
||||
#### Draft phase
|
||||
|
||||
During the draft phase, a new UTXO at the proposal script has been created. At this stage, only votes in favor of co-signing the draft are counted. For the proposal to transition to the voting phase, a threshold of GT will have to be staked backing the proposal. This threshold will be determined on a per-system basis and could itself be a 'governable' parameter.
|
||||
During the draft phase, a new UTXO at the proposal script has been created. At this stage, only votes in favor of co-signing the draft are counted. For the proposal to transition to the voting phase, a threshold of GT will have to be staked backing the proposal. This threshold will be determined on a per-system basis and could itself be a 'governable' parameter. It's important to note that cosignatures are not locking votes. Cosignatures are more like a delegated approval to a proposal. The sum of all cosignatures must tally to the threshold, and all cosigner stake datums must fit into a single transaction to witness their size.
|
||||
|
||||
#### Voting phase
|
||||
|
||||
|
|
@ -84,3 +80,46 @@ Failed proposals will not be interacted with further. The only value they will c
|
|||
Successful proposals will be verified by the governor component, which will issue ['governance authority tokens'](/docs/tech-design/authority-tokens.md) (GATs) to a proposal's separate 'effects'. The burning of these tokens will be a pre-requisite for system changes to be made, therefore the possession of one will serve as a form of 'licence' for making the changes.
|
||||
|
||||
There will be a deadline before which a proposal's effects will have to be executed. As any passed proposal's effects will necessarily have been supported by the community, it can be presumed that community members will have be incentivised to ensure the effects are enacted soon after the proposal has been passed.
|
||||
|
||||
#### Encoding of results
|
||||
|
||||
Most proposals are simply looking for approval for a particular transaction to take place. We encode the potential outcomes of the proposal in the following way (calling them "effects"):
|
||||
|
||||
```haskell
|
||||
type Effect =
|
||||
-- Effect validator hash
|
||||
( ValidatorHash
|
||||
-- Hash of datum sent to effect validator with GAT
|
||||
, DatumHash
|
||||
)
|
||||
|
||||
-- We need to tag the various possible outcomes with some sort of tag.
|
||||
data ResultTag = ResultTag Integer
|
||||
|
||||
-- Finally, we can encode all possible outcomes, each having zero or more effects.
|
||||
data ProposalDatum = ProposalDatum
|
||||
{ ... -- omitted
|
||||
, effects :: Map ResultTag [Effect]
|
||||
}
|
||||
```
|
||||
|
||||
In order to now encode a simple approval vote as described above, we just need to encode both the approval and disapproval outcomes:
|
||||
|
||||
```haskell
|
||||
yesNo :: [Effect] -> Map ResultTag [Effect]
|
||||
yesNo positiveEffects =
|
||||
Map.fromList
|
||||
[ -- Proposal didn't gain approval, nothing happens.
|
||||
(ResultTag 0, [])
|
||||
-- Proposal gained approval, the effects promised are executed.
|
||||
, (ResultTag 1, yes)
|
||||
]
|
||||
```
|
||||
|
||||
Encoding multiple different outcomes is possible by adding more pairs to the map. As part of validation of creation of a proposal, it's important to ensure that there is always a "negative" outcome. Otherwise an attacker could create a proposal that encodes two different outcomes, yet with both a net-negative towards the system.
|
||||
|
||||
#### Proposal metadata
|
||||
|
||||
Proposals carry very little metadata in their datums. They carry only their id -- which identifies them in a convenient incremental number -- and their original cosigners. The rest is data required for their functioning. It may however be useful to carry some extra metadata on-chain in order for the front-end to be able to identify and display relevant information to the users.
|
||||
|
||||
In order to achieve this, we can, upon the creation of a proposal, pass along the relevant information in the metadata field. Establishing a standard for how this should be laid out is yet to be done, but it could look as simple as a number of fields indicating the title, description, tags, etc. Since this metadata is only present in the creation of the proposal, it won't add to the transaction size for future transactions belonging to the proposal. The information can still be looked up by looking at the mint transaction of that particular proposal state thread.
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ The script for an Agora treasury is described in this section. For clarity, all
|
|||
|
||||
### Datum
|
||||
|
||||
```hs
|
||||
```haskell
|
||||
newtype TreasuryDatum = TreasuryDatum
|
||||
{ -- | Currency symbol of the treasury state thread.
|
||||
stateThread :: CurrencySymbol
|
||||
|
|
@ -63,7 +63,7 @@ newtype TreasuryDatum = TreasuryDatum
|
|||
|
||||
### Redeemers
|
||||
|
||||
```hs
|
||||
```haskell
|
||||
newtype TreasuryRedeemer = AlterTreasuryParams
|
||||
```
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ At the current stage, it is sufficient to allow users to simply grant funds to t
|
|||
|
||||
### Validators
|
||||
|
||||
```hs
|
||||
```haskell
|
||||
treasuryV ::
|
||||
CurrencySymbol ->
|
||||
TreasuryDatum ->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue