relink all tech-design docs to Notion
This commit is contained in:
parent
49871ae350
commit
8435552ab1
9 changed files with 5 additions and 619 deletions
10
README.md
10
README.md
|
|
@ -23,23 +23,23 @@ Open a development shell with `nix develop` and build the project with `cabal bu
|
|||
|
||||
## Documentation
|
||||
|
||||
Documentation for Agora may be found in [docs](./docs).
|
||||
Documentation for Agora is hosted on Notion. You can find the specs [here](https://liqwid.notion.site/e85c09d2c9a542b19aac8dd3d6caa98b?v=d863219cd6a14082a661c4959cabd6e7).
|
||||
|
||||
Haddock is deployed on GitHub Pages [here](https://liqwid-labs.github.io/agora/).
|
||||
|
||||
### Using Agora for your protocol
|
||||
|
||||
If you are a protocol wanting to use Agora, read [Using Agora](./docs/using-agora.md).
|
||||
If you are a protocol wanting to use Agora, read [Using Agora](https://liqwid.notion.site/Using-Agora-74ceb4a70d024992abd9ff07087013e6).
|
||||
|
||||
## Road-map
|
||||
|
||||
### v1
|
||||
|
||||
- [ ] Governor
|
||||
- [ ] Treasury
|
||||
- [x] Governor
|
||||
- [x] Treasury
|
||||
- [ ] Staking pool
|
||||
- [ ] Proposals
|
||||
- [ ] Effects
|
||||
- [x] Effects
|
||||
|
||||
### v2
|
||||
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
# Authority token technical design
|
||||
|
||||
| Specification | Implementation | Last revision |
|
||||
|:-----------:|:-----------:|:-------------:|
|
||||
| WIP | WIP | 2022-02-02 |
|
||||
|
||||
***
|
||||
|
||||
**Specification owner:** [Emily Martins]
|
||||
|
||||
**Authors**:
|
||||
|
||||
- [Emily Martins]
|
||||
- [Jack Hodgkinson]
|
||||
|
||||
**Implementation owner:** [Emily Martins]
|
||||
|
||||
[Emily Martins]: https://github.com/emiflake
|
||||
|
||||
[Jack Hodgkinson]: https://github.com/jhodgdev
|
||||
|
||||
[Peter Dragos]: https://github.com/peter-mlabs
|
||||
|
||||
**Current status:**
|
||||
|
||||
Initially written up by [Emily Martins] for Liqwid. Transferred across to Agora. Rewritten by [Jack Hodgkinson]. Outstanding suggestions from [Peter Dragos] that require addressing.
|
||||
|
||||
***
|
||||
|
||||
## Authority tokens
|
||||
|
||||
In the spirit of extensibility, a governance system should be able to readily expand the effects proposals can have on their protocol. With Ethereum systems, this is often done with untyped data and references to specific contract hashes. [Compound](https://medium.com/compound-finance/compound-governance-5531f524cf68) encodes an array of the contracts' addresses (`address[] Proposal.targets`) and the data to be passed to them (`bytes[] Proposal.calldatas`). This does not translate to Cardano's EUTXO model, so we require an alternative approach.
|
||||
|
||||
Our approach relies on two core assumptions:
|
||||
|
||||
- We trust the community to thoroughly assess the effects of a proposal. This ensures that the effects are safe and will work as intended.
|
||||
|
||||
- The effects of a proposal may only alter the system, after their associated proposal has been passed by the community.
|
||||
|
||||
The first assumption is justified by the fact that any proposal stores the hash of its effects' codes, and these effects are available for any user to inspect. The community of GT-holders will be able to verify a proposal's purported benefits.
|
||||
|
||||
To ensure the latter assumption holds true, we introduce 'governance authority tokens' (GATs). Any effect that wishes to alter the system will be required to _burn_ a GAT, when it is enacted. These GATs will be issued to a proposal's effects via the governor component, which has the responsibility of ensuring that a proposal passed in a correct and valid manner. Conceptually, the ownership of a GAT by an effect is a way of demonstrating to a component: 'the DAO (decentralised autonomous organisation) has granted me permission to alter your parameters'.
|
||||
|
||||
> The components that need to be adjustable at a later point will need to allow this as means for proving authority and validation of a transaction. So, for example, a Liqwid market might need to have its parameters updated, the following diagram shows how this would happen after a proposal has successfully been voted on and passed:
|
||||
|
||||
This model naturally requires that any component of the system, desired to be adjustable via governance is aware of the existence and significance of GATs. For example, a [Liqwid](https://github.com/mlabs-haskell/liqwid-contracts/) market may be subject to the effects of a successful proposal to alter its parameters. The following diagram shows how such an update would occur:
|
||||
|
||||

|
||||
|
||||
> Peter, 2022-01-24: You should add a link to what conventions you're following for you UTXO flows to the README
|
||||
|
||||
> Peter 2022-01-24: I think I see what's going on here, but it could use some annotations/additional description.
|
||||
> Tx1, a.) A proposal is closed via Tx1, and the transaction emits a continuing `Proposal` and `Governance` UtXO,
|
||||
> along with an "Effect" UTxO (presumably identified in the content of the proposal). The Effect UTxO encodes effect `f` in it's validation logic.
|
||||
> Question: where is this effect encoded?
|
||||
> Tx1, b.) In the same transaction, a GAT is minted and paid to the UTxO.
|
||||
> Tx1, c.) The `min utxo` ADA is paid to the Effect UTxO from "user inputs". I'm not certain where this is, but I'm assuming it's accumulated during voting or something? What is it used for?\
|
||||
> Tx2, a.) The Effect UTxO and the component to be governed are consumed in transaction 2.\
|
||||
> Tx2, b.) The Market's usual validation logic is short-circuited since the GAT was burned, and the continuing Market UTxO updates its datum.
|
||||
> Tx2, c.) There is a continuing "Effect" UTxO; presumably, this serves as a proof that an effect has taken place? Meaning that a sequence of effects that require a particular order of execution can consume the output UTxO as a witness?
|
||||
> Tx2, d.) The min ADA is paid to "user outputs"; is this just "collateral" to make sure that the effect is executed in a timely fashion?
|
||||
|
||||
This approach has a number of benefits but some important details must be kept in mind:
|
||||
|
||||
#### Handling multiple effects in a single proposal
|
||||
|
||||
Cardano script sizes are restricted to 16KB and previous proposal/effect models have had difficulties generating scripts which keep under this limit. By decoupling proposals and their effects, a proposal can have a far greater number of effects, as all it contains is a list of hashes for said effects. Effects themselves can make any number of changes to the system, as long as the resulting script is kept to an allowable size.
|
||||
|
||||
It is essentially impossible for the system to prevent conflicting effects taking place in short order and harming the system but the likelihood of this occurring is sufficiently reduced by all effects first having be passed by the DAO. There is scope for adding a notion of 'expiration', after which effects will no longer be able to enact their changes.
|
||||
|
||||
#### Writing effect code requires a _lot_ of care
|
||||
|
||||
The ability to alter large swathes of the system being conferred by the ownership of a single token poses the risk of (purposeful or inadvertent) harm. There are steps one can take to lessen this risk:
|
||||
|
||||
- All validators for an effect transaction are specified **in full**. In comparison to the normal writing of validators, where one only specifies what they must, one must do all they can to avoid undesired behaviour being permitted by the validator.
|
||||
- All transactions are only executed by one of a few 'trusted' DAO members. This would necessarily have to be encoded in the effect.
|
||||
|
||||
This should be sufficient to prevent loopholes. Delegating authority through validation or movement of tokens is often a necessary risk in blockchain systems and this problem is no more complex than others of its kind.
|
||||
|
||||
There is scope for expanding GATs to make them more restrictive and therefore less dangerous. One proposal is to store the hash of the effect script within the GAT, thus allowing for the minting of 'bespoke GATs', which are only authorised to make changes allowed for in the effect hash.
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
# Effects technical design
|
||||
|
||||
| Specification | Implementation | Last revision |
|
||||
|:-----------:|:--------------:|:-------------:|
|
||||
| WIP | WIP | v0.1 2022-04-11 |
|
||||
|
||||
---
|
||||
|
||||
**Specification ownership:** [Jack Hodgkinson]
|
||||
|
||||
**Authors**:
|
||||
|
||||
- [Jack Hodgkinson]
|
||||
|
||||
**Implementation ownership:** _unassigned_
|
||||
|
||||
[Jack Hodgkinson]: https://github.com/jhodgdev
|
||||
|
||||
**Current Status**:
|
||||
|
||||
First draft of effect article. Subject to review from @emiflake.
|
||||
|
||||
---
|
||||
|
||||
[Proposals](proposals.md) in a governance system are necessarily going to perform some actions or alter some parameters (otherwise, what's the point?). Due to script size limitations on Cardano, it is difficult to encapsulate all of a proposal's effects alongside other necessary information, such as vote counts. Rather than be constrained by such limitations, Agora _decouples_ proposals from their effects.
|
||||
|
||||
Effects will exist as their own scripts on the blockchain and proposals will simply include a list of an effect's hashes. This way, users are still able to identify the changes a given proposal would make to the system and thereby assess the proposal's desirability.
|
||||
|
||||
A proposal's effects will be initiated by the community, whom we assume will have sufficient incentive to pay the required transaction fee. However, if these effects are independent scripts, sitting there waiting to be initiated, how can we trust community members to only activate the effects of _passed_ proposals?
|
||||
|
||||
We don't. Effects will be _unable_ to alter the system without burning [_governance authority tokens_ (GATs)](authority-tokens.md). These are bestowed upon an effect, via the [governor](governor.md), if their associated proposal has been passed by the community.
|
||||
|
||||
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!"/>
|
||||
</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.
|
||||
|
||||
Conceiving of proposals this way makes them only marginally less powerful, as users will be able to combine effects in such a way as to render the desired effect. It does however prevent a user wishing to issue a proposal from having to construct their effects from whole cloth.
|
||||
|
||||
Whilst Agora may offer this functionality, there is nothing stopping DAO members from writing their own effect code.
|
||||
|
||||
## The issue of partial execution
|
||||
|
||||
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).
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
# Governor technical design
|
||||
|
||||
| Specification | Implementation | Last revision |
|
||||
|:-----------:|:--------------:|:-------------:|
|
||||
| WIP | WIP | v0.1 2022-02-03 |
|
||||
|
||||
---
|
||||
|
||||
**Specification ownership:** [Jack Hodgkinson]
|
||||
|
||||
**Authors**:
|
||||
|
||||
- [Jack Hodgkinson]
|
||||
- [Emily Martins]
|
||||
|
||||
**Implementation ownership:** _unassigned_
|
||||
|
||||
[Jack Hodgkinson]: https://github.com/jhodgdev
|
||||
|
||||
[Emily Martins]: https://github.com/emiflake
|
||||
|
||||
**Current Status**:
|
||||
|
||||
First draft.
|
||||
|
||||
---
|
||||
|
||||
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.
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
# Proposals technical design
|
||||
|
||||
This document gives an overview of the technical design of the proposals system for introducing, voting on and executing governance proposals.
|
||||
|
||||
| Specification | Implementation | Last revision |
|
||||
|:-----------:|:-----------:|:-------------:|
|
||||
| WIP | WIP | v0.1 2022-04-27 |
|
||||
|
||||
---
|
||||
|
||||
**Specification ownership:** [Emily Martins]
|
||||
|
||||
**Authors**:
|
||||
|
||||
- [Emily Martins]
|
||||
- [Jack Hodgkinson]
|
||||
|
||||
**Implementation ownership:** [Emily Martins]
|
||||
|
||||
[Emily Martins]: https://github.com/emiflake
|
||||
|
||||
[Jack Hodgkinson]: https://github.com/jhodgdev
|
||||
|
||||
**Current status**:
|
||||
|
||||
Imported from Liqwid by [Emily Martins]. Underwent rewrite by [Jack Hodgkinson].Further amendments to the 'period table' should be considered.
|
||||
|
||||
---
|
||||
|
||||
## Proposals
|
||||
|
||||
Initiating a proposal requires the proposer to have more than a certain amount of GT staked in the system e.g. 5GT. This is checked by consuming the UTXO representing the user's stake. Initiating a proposal creates a script, which will handle all voting interactions.
|
||||
|
||||
## Voting
|
||||
|
||||
### Voting stages
|
||||
|
||||
The life-cycle of a proposal is neatly represented by a state machine, with the 'draft' state being the initial state, and 'executed' and 'failed' being the terminating states.
|
||||
|
||||
Note: this state-machine representation is purely conceptual and should not be expected to reflect technical implementation.
|
||||
**Please note that this state-machine representation is purely conceptual and should not be expected to reflect technical implementation.** This is because some transitions in the state machine representation don't need to happen on-chain, as a transaction. A key example of this is a proposal going from the "lock" phase to the "execution" phase. No on-chain transition takes place: it is simply that we have reached the time in the real-world, when the proposal is allowed to be executed.
|
||||
|
||||
To make the following diagram clear, we employ the following terminology:
|
||||
|
||||
|
||||
> state
|
||||
> A 'state' in our conceptual FSM representation above. Useful for thinking about proposals. Does not necessarily reflect a change occurring on-chain.
|
||||
|
||||
|
||||
> period
|
||||
> A segment of real-world, POSIX time. As we transition from one period to another, a proposal's status (see below) will not be updated.
|
||||
|
||||
|
||||
> status
|
||||
> The 'status' of a proposal is stored in the proposal's datum and is thus always represented on-chain. Changing this requires a transaction to take place.
|
||||
|
||||
|
||||

|
||||
|
||||
#### 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. 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. A limit on the maximum amount of cosigners is placed in order to prevent a situation where the stake datums no longer fit in the transaction. The number doesn't matter and may be expressed in a parameterized way.
|
||||
|
||||
#### Voting phase
|
||||
|
||||
In the voting phase, users may utilise their stakes to vote in-favour or in-opposition to a proposal. This will add their vote to the relevant count. There is potential for contention within the system and therefore voting on proposals may have to be rate-limited. The method by which a user's stakes are weighted and the thresholds required for proposals to pass are determined on a per-protocol basis.
|
||||
|
||||
#### Lock phase
|
||||
|
||||
Upon completion of the voting phase, a proposal will either have been passed or failed. A delay between the passing of a proposal and execution of its effects will be enforced, to allow users to prepare for incoming changes to the system. It'll further give the system maintainers opportunity to intervene, in the case of a hostile action.
|
||||
|
||||
#### Execution phase
|
||||
|
||||
Failed proposals will not be interacted with further. The only value they will contain is their state thread tokens and the minimum ADA requirement, so little of worth is lost.
|
||||
|
||||
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.
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
# Safety Pool functionality for the Staking Pool
|
||||
|
||||
| Specification | Implementation | Last revision |
|
||||
|:-----------:|:-----------:|:-------------:|
|
||||
| WIP | WIP | 2022-05-13 |
|
||||
|
||||
---
|
||||
|
||||
**Specification ownership:** [Emily Martins]
|
||||
|
||||
**Authors**:
|
||||
|
||||
- [Emily Martins]
|
||||
|
||||
**Implementation ownership:** [Emily Martins]
|
||||
|
||||
[Emily Martins]: https://github.com/emiflake
|
||||
|
||||
[Jack Hodgkinson]: https://github.com/jhodgdev
|
||||
|
||||
**Current status:** Early revision of the document with low technical specification due to feature being further in the timeline. Has been reviewed by [Jack Hodgkinson].
|
||||
|
||||
---
|
||||
|
||||
In order for Agora’s staking pool to act as a *safety pool*, it needs to be able to support a workflow for slashing staked governance tokens (GT) to act as a safety mechanism. (Note: we use "slashing" to mean taking away some token from a particular user.) This document outlines the changes that need to be made to Agora in order to support this.
|
||||
|
||||
### Motivation
|
||||
|
||||
In the event of a protocol suffering loss of funds through a [shortfall event](https://docs.aave.com/aavenomics/safety-module#shortfall-events), slashing a percentage of locked GT can be used to attempt a recovery. Ultimately, doing this is beneficial for the stakeholders because it allows the protocol to recover and eventually benefits them as well (even though they bear the initial cost). Striking a balance (in the form of the right percentage slashed) is important in order for stakeholders to want to vote in favour of a proposal that results in such a slashing.
|
||||
|
||||
## Slashing functionality
|
||||
|
||||
In order to allow an admin to withdraw a set percentage of the amount staked, we create a new effect.
|
||||
|
||||
### The `SlashEffect` validator:
|
||||
|
||||
- Mint a `SlashToken` and send it to a validator ("the `Slash` validator") with a datum encoding the details of the slashing.
|
||||
|
||||
The `SlashDatum` could look like this:
|
||||
|
||||
```haskell
|
||||
data SlashDatum = SlashDatum
|
||||
{ -- | Identify which slash event this datum belongs to.
|
||||
slashId :: Integer
|
||||
, -- | Represents how much is to be slashed (as a ratio of the full staked amount).
|
||||
slashPercentage :: Rational
|
||||
, -- | The time range that must contain `txInfoValidRange` in order to slash.
|
||||
slashTimeRange :: POSIXTimeRange
|
||||
}
|
||||
```
|
||||
|
||||
- `SlashDatum` must, in some way, be present in the datum that is passed to the `SlashEffect` validator. This means that the `ProposalDatum` also indirectly contains `SlashDatum`.
|
||||
|
||||
### The `SlashToken` policy:
|
||||
|
||||
- Exclusively check for GAT burn. Delegated checking goes to the `SlashEffect` validator.
|
||||
- This `SlashToken` policy needs to be "known" by the Stake validator, in order to allow transactions to take place.
|
||||
|
||||
### The `Slash` validator:
|
||||
|
||||
- This validator allows spending of a percentage of a `Stake`s GT, provided a few conditions are met:
|
||||
- The `SlashToken` is present
|
||||
- The slash ID is tagged onto the new stake datum
|
||||
- The time range encoded in the `SlashDatum` includes the `txInfoValidRange`.
|
||||
- What is done with the recovered GT is up to the admin to determine. Q: Is this what we want?
|
||||
|
||||
Finally, we need to change `StakeDatum` to encode a list of slash IDs in order to prevent slashes happening twice.
|
||||
|
||||
---
|
||||
|
||||
## Preventing opting out of slashing
|
||||
|
||||
If this is where we call it quits, then users will each be able to just opt-out of this slashing event. GT holders are individually incentivized to do so, because it means they don’t forfeit their own assets. Obviously, then, in order to make the safety pool work at all, we need to prevent this.
|
||||
|
||||
### Time-locking stakes
|
||||
|
||||
A simple solution is time-locking stake withdrawal upon any interaction with it for a set amount of days. This ought to be long enough for a full proposal to go through, but not too long for it to become annoying for users of the staking pool. This presents a big drawback in general for all stakeholders as their assets are actually locked even though no slashing necessarily will ever happen. However, this is also a very simple solution for solving the opt-out problem. It should be something we can enable or disable after the fact, as well as in initial configuration.
|
||||
|
||||
### CIP-31 dependent central lock
|
||||
|
||||
Provided we have reference-inputs ([CIP-31](https://cips.cardano.org/cips/cip31/)) by the time we implement this, an alternative approach is viable:
|
||||
|
||||
- We create a script that manages a `StakeLockDatum`. The script (”`StakeLock` validator”) encodes whether or not `Stake`s are allowed to withdraw. Using reference-inputs, we are able to witness this datum without consuming it, allowing us to lose no throughput on withdrawals, while maintaining a centralized lock.
|
||||
- The `StakeLock` validator can only set to lock through an admin-controlled multisig. The admin multisig should do this in the event that a proposal has been created for the shortfall event.
|
||||
- The `StakeLock` utxo can be consumed by anyone after a set period of time, unlocking it again. This prevents admins from abusing the locking for whatever reason.
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
# Stakes and staking pool technical design
|
||||
|
||||
| Specification | Implementation | Last revision |
|
||||
|:-----------:|:-----------:|:-------------:|
|
||||
| WIP | WIP | 2022-02-07 |
|
||||
|
||||
---
|
||||
|
||||
**Specification ownership:** [Emily Martins]
|
||||
|
||||
**Authors**:
|
||||
|
||||
- [Emily Martins]
|
||||
- [Jack Hodgkinson]
|
||||
|
||||
**Implementation ownership:** [Emily Martins]
|
||||
|
||||
[Emily Martins]: https://github.com/emiflake
|
||||
|
||||
[Jack Hodgkinson]: https://github.com/jhodgdev
|
||||
|
||||
**Current status:** Originally written for Liqwid by [Emily Martins]. Rewritten by [Jack Hodgkinson]. Required review from [Emily Martins], especially the section on staking pools.
|
||||
|
||||
---
|
||||
|
||||
## Stake UTXOs
|
||||
|
||||
A 'stake' records how much GT has been staked by a user, and on which proposals it has been locked against.
|
||||
|
||||
```haskell
|
||||
data Stake = Stake
|
||||
{ -- | Which proposals has this stake been used to vote on?
|
||||
lockedByProposals :: [(DatumHash, ProposalVote)]
|
||||
, -- | The amount of GT in the stake.
|
||||
stakedAmount :: GT
|
||||
, -- | The owner of the stake.
|
||||
owner :: PubKeyHash
|
||||
}
|
||||
```
|
||||
|
||||
When voting for a proposal, the stake UTXO is used to witness the user's staked amount. As a result, the two following state transitions take place:
|
||||
|
||||
```haskell
|
||||
proposal.votes += (stake.stakedAmount, vote)
|
||||
stake.lockedByProposals += (hash proposal.settings, vote)
|
||||
```
|
||||
|
||||
This forms a mutual binding between the proposal and the stake.
|
||||
|
||||
A stake may be used to vote on an unlimited number of proposals. Consider a user staking 50GT. They may pledge that 50GT against a proposal `p` _and_ another proposal `q`.
|
||||
|
||||
Altering the amount positioned in a stake is not possible, for as long as that stake is locked against any proposals. This is to prevent vote manipulation. Consider:
|
||||
|
||||
- Ford stakes 100GT and votes in-favour of a proposal `p`. `p` now has +100GT in-favour.
|
||||
- Ford _increases_ his stake by 50GT to 150GT.
|
||||
- Ford retracts his vote from `p`. As his stake is 150GT, `p` deducts 150GT and `p` now has -50GT in-favour.
|
||||
|
||||
It should be clear how users could alter their stakes to reduce and manipulate the vote count. Preventing alteration of GT in stakes ensures that there is never a discrepancy between the amount of GT a user holds and the amount the system believes that they hold.
|
||||
|
||||
If a user wished to stake _more_ GT, they could always create a new stake that they would be free to lock on proposals. For this reason, it may be useful to include a method of 'merging' stakes, when they are not being locked against any proposals, to allow users to 'streamline' their GT portfolio.
|
||||
|
||||
## Delegating stake
|
||||
|
||||
Aspects of delegation, such as co-signing work through the trivial witnessing of a stake UTXO, however allowing a user to delegate their stakes requires an extra field:
|
||||
|
||||
```haskell
|
||||
data Stake = Stake
|
||||
{ -- | Which proposals has this stake been used to vote on?
|
||||
lockedByProposals :: [(DatumHash, ProposalVote)]
|
||||
, -- | The amount of GT in the stake.
|
||||
stakedAmount :: GT
|
||||
, -- | The owner of the stake.
|
||||
owner :: PubKeyHash
|
||||
, -- | To whom this stake has been delegated.
|
||||
delegatedTo :: Maybe ValidatorHash
|
||||
}
|
||||
```
|
||||
|
||||
When voting on a proposal, a user can check which stakes have delegated to them off-chain and include them in the voting transaction. _This will lock the delegator's stake_, however they will be themselves be able to unlock it as usual. It should be noted that delegation of stakes only extends to voting on proposals and not, for example, withdrawing GT from a stake.
|
||||
|
||||
## Destroying stake
|
||||
|
||||
In order to recover the ADA spent on creating the stake UTXO (and any other funds, which may have been locked by accident), stake UTXOs must be destroyable. As is the case with the depositing and withdrawal of GT from a stake, the stake must *not* be locked by any proposals, before it may be destroyed.
|
||||
|
||||
|
||||
## Staking pool
|
||||
|
||||
There are a number of reasons that a protocol would wish to track the global state of stakes in its system. For example, a protocol may wish to implement a proposal system where a certain proportion of the globally available GT must be staked in-favour of a proposal, in order to allow it to pass. This is the equivalent of mandating a certain voter turnout be met in a national referendum. The ability to do such a thing is conferred by the creation of a _staking pool_.
|
||||
|
||||
Whilst the ability to track stakes is a useful one, it is a complicated concept to implement on Cardano. A particular issue is _throughput and contention_: any purely on-chain solution is unlikely to be able to process data rapidly enough that the process of users creating stakes _and_ updating the staking pool is as seamless as desired.
|
||||
|
||||
One potential solution for this is an _escrow_ system, which implements a queueing solution by which users issue their stake and the system takes responsibility for updating the staking pool accordingly, with no further action required from the staker. This is a feature that is being considered for Agora v2.
|
||||
|
||||
Another implementation takes the burden of calculating the global state of user stakes _off-chain_. This allows the developers much more freedom in how they approach the solution, as they are no longer restricted by the complications of programming on a blockchain. What issue this solution _does_ have is one of **trust**. Any off-chain solution utilised by the protocol developers must demonstrate its fairness and accuracy to its users.
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
# Treasury technical design
|
||||
|
||||
| Specification | Implementation | Last revision |
|
||||
|:-----------:|:--------------:|:-------------:|
|
||||
| Draft | WIP | v0.1 2022-03-04 |
|
||||
|
||||
---
|
||||
|
||||
**Specification ownership:** [Jack Hodgkinson]
|
||||
|
||||
**Authors**:
|
||||
|
||||
- [Jack Hodgkinson]
|
||||
|
||||
**Implementation ownership:** [Jack Hodgkinson]
|
||||
|
||||
[Jack Hodgkinson]: https://github.com/jhodgdev
|
||||
|
||||
[Emily Martins]: https://github.com/emiflake
|
||||
|
||||
**Current Status**:
|
||||
|
||||
- Conceptual draft agreed upon.
|
||||
- Implementation incomplete; documentation subject to change.
|
||||
|
||||
---
|
||||
|
||||
Treasuries in Cardano governance systems serve two functions:
|
||||
|
||||
1. To serve as a community reserve or wallet.
|
||||
2. To allow users to redeem their allocated share of rewards.
|
||||
|
||||
## Community reserve
|
||||
|
||||
A decentralised autonomous organisation (DAO) may wish to source funds from its members to save for use at a later date. A treasury therefore serves as a form of 'community wallet', where members can contribute funds, knowing that they may only be released at the behest of the community.
|
||||
|
||||
Treasuries are not, by default, limited to the reserve of a single token and are indeed able to hold any supported Cardano tokens.
|
||||
|
||||
A treasury, as a community's reserves, will naturally need to interact with governance proposals. Indeed, the primary mechanism by which funds are able to be released by the treasury, will be the passing of an appropriate proposal.
|
||||
|
||||
## Reward holder
|
||||
|
||||
The treasury will further be the initial holder of all a governance system's GT. It is likely that any governance system will desire a method to distribute these GT through the community _over time_. The amount of GT a DAO member is eligible for at a given time can be termed that user's 'reward'. The specifics of any 'reward structure', namely:
|
||||
|
||||
1. Who is eligible for rewards?
|
||||
2. When may they receive those rewards?
|
||||
3. How much do they receive in their reward?
|
||||
|
||||
are all, naturally, protocol-specific. A simple method for creating such a bespoke reward structure is **not** considered in-scope for Agora v1. Agora v1 will offer a simple, prescribed reward structure, that allows the treasury to determine the reward eligibility of a user and allow them to redeem said amount.
|
||||
|
||||
## Script
|
||||
|
||||
The script for an Agora treasury is described in this section. For clarity, all data types and functions are written in _traditional Haskell_, rather than at the Plutarch level.
|
||||
|
||||
### Datum
|
||||
|
||||
```haskell
|
||||
newtype TreasuryDatum = TreasuryDatum
|
||||
{ -- | Currency symbol of the treasury state thread.
|
||||
stateThread :: CurrencySymbol
|
||||
}
|
||||
```
|
||||
|
||||
### Redeemers
|
||||
|
||||
```haskell
|
||||
newtype TreasuryRedeemer = AlterTreasuryParams
|
||||
```
|
||||
|
||||
At the current stage, it is sufficient to allow users to simply grant funds to the treasury, without an explicit redeemer. The only redeemer that is required is `AlterTreasuryParams`, for when the treasury's parameters are subject to change by a proposal effect.
|
||||
|
||||
### Validators
|
||||
|
||||
```haskell
|
||||
treasuryV ::
|
||||
CurrencySymbol ->
|
||||
TreasuryDatum ->
|
||||
TreasuryRedeemer ->
|
||||
ScriptContext ->
|
||||
()
|
||||
```
|
||||
|
||||
The only redeemer the validator handles at present is `AlterTrParams`. The validator ensures that a valid governance authority token is burned, when a proposal effect is attempting to alter the parameters of the treasury.
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
# Using Agora
|
||||
|
||||
## Motivation
|
||||
|
||||
If you are building a project on Cardano that involves decentralized interaction between users you may want to create a DAO ([Decentralized Autonomous Organization](https://www.wikiwand.com/en/Decentralized_autonomous_organization)).
|
||||
|
||||
A DAO will allow users to come to a consensus on a variety of matters relevant to your project. These could include: managing of treasury assets, changing of protocol parameters, replacing of scripts, deprecation of the protocol in favour of a new version, emergency actions to protect users, and so forth. In order to do this on-chain, users will have to be able to express their opinion contractually, and only those with a vested interest ought to be able to interact with relevant proposals. This should ensure that voters have the best interests of the protocol at-heart. Governance systems can take varied forms, and not all of them will be suitable for your project.
|
||||
|
||||
Building such a system is a complex process and requires a lot of care; ensuring fairness (with regard to user interactions), efficiency (with regard to contention and throughput) and simplicity (with regard to script size and transaction costs). Agora is a curated set of scripts, types and design patterns that are designed from the ground-up to solve this problem in a way that is flexible enough to suit essentially any protocol.
|
||||
|
||||
### A quick note on terms
|
||||
|
||||
This article will include common English words that have specific meanings in Agora. To help you disambiguate, here are some definitions:
|
||||
|
||||
- proposal: A collection of changes to the protocol, which are voted on as a block.
|
||||
- effect: An on-chain representation of a proposed change to the protocol. A 'proposal' will hold references to one or many 'effects'. If an effect's proposal is passed by the community, effects are granted special 'authority tokens' which permit them to enact their encoded changes to the relevant protocol components.
|
||||
|
||||

|
||||
|
||||
## Agora and your protocol
|
||||
|
||||
Agora’s staking model relies on the existence of a governance token. In a sense, this governance token _parameterizes_ the entire system. Agora staking pools will lock users' governance tokens in order to permit them to vote. Agora's components are free-standing and don't _require_ a protocol acting in a particular way in order to function. One could for instance technically create a DAO that works with ADA as its governance token. The tokenomics of your governance token will of course influence the way voting power is distributed, due to the nature of token-based voting.
|
||||
|
||||
In order to set-up your protocol’s DAO actions, all affected components of your protocol will need to interpret the burning of an _authority token_ as a licence to alter _any_ aspect of that component.
|
||||
|
||||
To put this in slightly more concrete terms: for any datum which holds a subset of your protocol's parameters, there _should_ exist a redeemer for that datum and validation for this datum/redeemer pair should do _no more_ than verify that one of these authority tokens has been burned. Without this flexibility, the effects of Agora's proposals would be markedly less powerful.
|
||||
|
||||
### Writing effects
|
||||
|
||||
One writes a proposal effect, as one would write any Plutus script with the caveat that the effect script will only be permitted to run _once_.
|
||||
|
||||
Consider an example NFT project, wherein the minting of each NFT is a community action. For this scenario, one would require a template `MintNFT` effect, which mints its corresponding NFT upon the passing of the relevant proposal. The proposal being passed will issue an authority token to the effect. Each NFT's policy will verify that such an authority token was burned upon minting, which demonstrates that the minting of the NFT was indeed authorized by the DAO.
|
||||
|
||||
Making your protocol's components aware of authority tokens, and implementing relevant effects are the only two chores of using Agora in practice. The former is the only one that involves adapting your own scripts. Effect scripts can be written after your protocol and its governance have deployed, provided that the authority tokens are respected by the components.
|
||||
|
||||
## What Agora leaves up to you
|
||||
|
||||
Agora’s concern is the on-chain components and scripts. Any front-ends are the concern of the protocol's developers. In the best case, our documentation and program design will inspire you in developing a front-end solution. There is scope for Agora containing some off-chain functionality in-future. This would allow the user to create and experiment with transactions.
|
||||
|
||||
It’s worth noting that, while the actual functionality of the _front-ends_ is not a concern, creating standards for off-chain metadata _is_. For example, metadata tagging proposal descriptions, tags, dates. These are all important features that Agora aims to standardize, in hopes of facilitating interoperability between various instances of Agora. This effort is similar to [CIP-25](https://cips.cardano.org/cips/cip25/), which aims to standardize metadata for NFTs.
|
||||
|
||||
You're welcome to write any new effects you require for your protocol. If you believe any effects you write are sufficiently general and could serve as a benefit to our community, we would encourage you to up-stream them. Guidelines for doing so may be found in our [contribution guide](/CONTRIBUTING.md). Agora provides a number of effects out-of-the-box and intends to add more with time.
|
||||
|
||||
## What to do if something is missing
|
||||
|
||||
In the event Agora does not provide for one of your use cases, feel free to raise an issue and we can begin a discussion on implementing the desired functionality. Our [contribution guide](/CONTRIBUTING.md) has guidelines for registering issues.
|
||||
Loading…
Add table
Add a link
Reference in a new issue