-
Notifications
You must be signed in to change notification settings - Fork 1
docs: Token Voting Module documentation #91
Changes from 17 commits
0628f93
ef39b5b
47f8918
deb30cf
2ac6988
937ee15
639923e
d402812
b3e619f
a3a7c59
2ffe5e7
549a3b0
c74e9b1
5770756
4e584c6
39a111a
f92cfec
612d2a3
405caf3
f47de62
9e813ca
f1c314b
6fdfe48
a5d0695
5279735
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Overview | ||
|
||
## What is Llama? | ||
|
||
Llama is an onchain governance and access control framework for smart contracts. | ||
|
||
Using Llama, teams can deploy fully independent instances that define granular roles and permissions for executing transactions, known as "actions". | ||
|
||
Llama instances can adapt to a changing environment by incrementally adding new participants and expanding the set of available actions. Actions can be any operation that is represented by invoking a smart contract function. This includes transferring funds, updating a registry, changing protocol parameters, or activating an emergency pause. | ||
|
||
Learn more about Llama by reading [the protocol documentation](https://github.com/llamaxyz/llama/tree/main/docs) in the llama repository. | ||
|
||
## What is Llama Periphery? | ||
|
||
This repository contains supporting modules for operating Llama instances. Modules are extensions to Llama instances that can be adopted by using a Llama action to configure and deploy. | ||
|
||
## Modules | ||
|
||
- [Token Voting](https://github.com/llamaxyz/llama-periphery/tree/main/docs/token-voting/README.md): smart contract policies that allow voting token holders to create actions enforced by delegated token thresholds or collectively approve or disapprove an action through token voting. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Llama Token Voting | ||
|
||
Token voting modules are extensions to Llama instances. They allow token holders to create actions and collectively cast approvals or disapprovals. The LlamaTokenGovernor contract follows established token voting framework best practices and is designed to integrate directly with instances. | ||
dd0sxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
The token voting module consists of two components: | ||
|
||
- [Token Governor](/docs/token-voting/TokenGovernor.md) | ||
|
||
- [Token Voting Factory](/docs/token-voting/Factory.md) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# Llama Token Governor | ||
|
||
The Token Governor is the contract that enables token holders to create actions and cast votes and vetoes. | ||
|
||
Llama Token Voting works by issuing a Llama policy to the `LlamaTokenGovernor` contract, which can hold roles and permissions that enable the contract to cast approvals/disapprovals and create actions. The Governor contract exposes this policyholder functionality via public functions to token holders. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be more grammatically correct to say the token voting module. I think it makes sense to capitalize Llama since it's a proper noun and contract names like |
||
|
||
## Voting Periods | ||
|
||
There are three distinct periods during a voting cycle: | ||
- The delay period | ||
- The voting/vetoing period | ||
dd0sxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- The submission period | ||
|
||
The token voting process begins with a delay period. This period is calculated by multiplying the `delayPeriodPct` by the action's approval or disapproval period. The purpose of the delay period is to provide token holders a window to delegate their tokens before voting balances are crystallized for the duration of the token vote. | ||
|
||
The voting period is when token holders vote/veto a pending action. It is calculated as the product of the `votingPeriodPct` and the action's approval or disapproval period. It automatically begins at the end of the delay period. | ||
|
||
Finally, the submission period is when the result is submitted to the instance's `LlamaCore` contract if consensus is reached. It is calculated by subtract the `delayPeriodPct` and `votingPeriodPct` from `ONE_HUNDRED_IN_BPS`. It automatically begins at the end of the voting period. | ||
|
||
## Casting Votes/Vetos | ||
dd0sxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
The Llama Token Governor contract allows token holders to participate in the governance process by casting votes or vetoes on actions. This functionality is crucial for the decentralized decision-making process, ensuring that the actions reflect the collective will of the token holders. | ||
|
||
### Delay Period | ||
|
||
Before voting begins, there is a delay period. The delay period allows token holders to delegate before the end of the delay period, and generally allows users to move tokens around or obtain tokens before a vote they want to participate in. After the delay period, the voting period begins automatically and tokenholders can begin to cast votes. Tokens obtained or delegated after the delay period has ended are not eligible to cast. If a token holder had tokens delegated at the end of the delay period and transfers them afterwards, they are still able to cast because these values are checkpointed. | ||
|
||
### Casting Votes | ||
|
||
Token holders can cast their votes during the voting period on actions created within the Llama governance system if the Governor holds the approval or force approval role for the action's strategy. The process of casting a vote involves indicating support or opposition to a particular action. The contract provides the `castVote` function, which requires the following parameters: | ||
|
||
```solidity | ||
uint8 role, | ||
ActionInfo actionInfo, | ||
uint8 support, | ||
string reason | ||
``` | ||
|
||
- Role: This parameter specifies the role of the token holder in the governance process. It is used to determine the permission ID of the Token Governor. | ||
- ActionInfo: This struct contains all the necessary information about the action on which the vote is being cast, including the action ID, creator, strategy, target, value, and data. | ||
- Support: Indicates the token holder's stance on the action. The values can be: | ||
- 0 for Against | ||
- 1 for For | ||
- 2 for Abstain | ||
- Reason: A human-readable string providing the rationale behind the token holder's vote. | ||
|
||
The function returns the weight of the cast, representing the influence of the token holder's vote based on their token balance. | ||
|
||
### Casting Vetos | ||
|
||
In addition to casting votes, token holders also have the ability to cast vetoes. | ||
|
||
The `castVeto` function is similar to castVote and requires the same parameters. The parameters have the same meaning as in the castVote function. The support parameter, in this context, indicates the token holder's stance on vetoing the action. | ||
|
||
### Reaching Quorum and Approval | ||
|
||
Quorum is calculated purely on the amount of `For` votes. `Abstain` votes do not count towards the quorum. | ||
dd0sxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Approval is reached when the quorum is met, and the For votes surpass the `Against` votes. | ||
dd0sxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### Submitting Results | ||
|
||
Once the voting period is over, the result can be submitted. | ||
|
||
If the action has not passed, no action needs to be taken. | ||
|
||
If the action has passed, anyone now can call the `submitApproval` or `submitDisapproval` function depending on if the action is being voted or vetoed. The submit functions must be called before the end of the submission period, otherwise it expires. | ||
|
||
## Creating Actions | ||
|
||
Token holders of a given governance token can create actions on the Llama instance if they have a sufficient token balance. | ||
dd0sxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
The `creationThreshold` is the number of tokens required to create an action. It is variable and therefore it can be updated. | ||
dd0sxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
To create an action, a user must call the `createAction` function which has the following fields: | ||
|
||
```solidity | ||
uint8 role, | ||
ILlamaStrategy strategy, | ||
address target, | ||
uint256 value, | ||
bytes data, | ||
string description | ||
``` | ||
|
||
- Role: The role that will be used to determine the permission ID of the Token Governor. | ||
- Strategy: The strategy contract that will determine how the action is executed. | ||
- Target: The contract called when the action is executed. | ||
- Value: The value in wei to be sent when the action is executed. | ||
- Data: Data to be called on the target when the action is executed. | ||
- Description: A human readable description of the action and the changes it will enact. | ||
|
||
Note that if the Governor itself does not have the permission to create the action on the instance's `LlamaCore`, `createAction` will fail. | ||
|
||
The action creation process is the same as the core Llama system, but instead of creating actions based on the user's policy and permissions the Governor's validation check is based on if they hold enough tokens. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would say something like if they hold more tokens than the creation threshold instead of hold enough tokens |
||
|
||
If you are not familiar with the canonical Llama action creation process, our the main [Llama docs](https://github.com/llamaxyz/llama/tree/main/docs) will help. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Llama Token Voting Factory | ||
|
||
The `LlamaTokenVotingFactory` contract enables the deployment of token voting modules. This factory contract deploys a new `LlamaTokenGovernor` and `LlamaTokenAdapter`. These two contracts comprise a token voting module which is how holders of a specified token can participate in Llama governance. | ||
|
||
## Deployment | ||
|
||
To Deploy a `LlamaTokenVotingFactory` through the llama token voting module factory, a `LlamaTokenVotingConfig` struct is passed to the deploy method on the factory contract. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Language standardization pass https://github.com/llamaxyz/llama-periphery/pull/91/files#r1440933498 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be consistent about including the fields of named structs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To respond to this I don't think we need to include the struct fields here since there are structs, and it doesn't help understanding |
||
|
||
At deploy time, a token adapter logic contract and config are passed to the factory's deploy function. | ||
|
||
### Token Adapters | ||
|
||
Token Adapters allow the Llama Token Governer to connect to many different implementations of tokens. | ||
|
||
We've implemented a token adapter that works with ERC20 and ERC721 tokens that implement the [IVotes interface](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/governance/utils/IVotes.sol) and checkpoint supply using `block.timestamp`. | ||
|
||
Many tokens checkpoint using `block.number`, or have different method names than the `IVotes` interface. The purpose of the adapter is to provide a constant interface for the governor, while being flexible to handle many different token implementations. | ||
|
||
Currently only timestamp based tokens are supported, but we can extend functionality to tokens that checkpoint in block number by writing a new adapter. | ||
dd0sxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
|
||
dd0sxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
## Integrating with a Llama instance | ||
|
||
After deploying your token voting module, you will need to create a dedicated role and issue a policy with the corresponding role to the `LlamaTokenVotingGovernor` contract. | ||
|
||
If you want token holders to approve or disapprove actions, you will need to create some strategies that utilize the Caster as the approval or disapproval role so that the token holders can actually vote on certain actions. | ||
|
||
Addisionally, you can issue permissions to the governor contract if you wish for policyholders to be able to create certain actions on your Llama instance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use consistent language. I've seen: