Skip to content
This repository has been archived by the owner on Nov 27, 2024. It is now read-only.

docs: Token Voting Module documentation #91

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/README.md
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.
9 changes: 9 additions & 0 deletions docs/token-voting/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Llama Token Voting
Copy link
Contributor

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:

  • Llama Token Voting
  • Llama Token Voting Module
  • Llama token voting governor contract
  • llama token voting module factory
  • LlamaTokenVotingFactory
  • Llama Token Voting Factory
  • token governor
  • Llama Token Governor


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)
97 changes: 97 additions & 0 deletions docs/token-voting/token-governor.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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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 LlamaTokenGovernor, but I don't see why Governor should be capitalized here


## 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.
Copy link
Contributor

@AustinGreen AustinGreen Jan 9, 2024

Choose a reason for hiding this comment

The 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.
29 changes: 29 additions & 0 deletions docs/token-voting/token-voting-factory.md
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be consistent about including the fields of named structs

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.
Loading