# Conviction Voting (CV)

Conviction Voting (CV) is a governance mechanism that allows users to signal their preference on various issues by staking their tokens on proposals. A proposal passes if it has sufficient weight allocated to it. The weight of a proposal is calculated based on the amount of tokens that have been staked and the amount of time these tokens have been staked. The [introduction to conviction voting](https://medium.com/commonsstack/announcing-the-conviction-voting-cadcad-model-release-8e907ce67e4e?ref=blog.ceramic.network) by Common Stack is a great primer if you want to learn more about how CV works.

Implementations of CV so far have been developed on the EVM, which makes the results and outcomes completely trustless. While there are some deployments like [1Hive](https://1hive.org/?ref=blog.ceramic.network) and [Common Stack](https://cv.commonsstack.org/?ref=blog.ceramic.network), high gas costs and the sub-optimal user experience of transferring tokens for every vote make this quite problematic. Fortunately conviction voting systems can be securely implemented using off-chain, verifiable data structures. Building CV systems off-chain, as opposed to on-chain, avoids the high gas costs and poor user experience that plagues current implementations while still achieving verifiability and participant trust.

This article will explain how you can use [IDX](https://idx.xyz/?ref=blog.ceramic.network) and [Ceramic Network](/content/?ref=blog.ceramic.network) as an underlying data structure to build a conviction voting dapp.

## Intro to Ceramic and IDX

**Ceramic** is a decentralized protocol for verifiable, version-controlled content. Ceramic is used to create mutable data on IPFS with permanent identifiers, called _StreamIDs_. All updates are signed and then periodically anchored into the blockchain for time-stamping and consensus. You can think of a single Ceramic stream as its own ledger which contains all the information needed to reconstruct the state of the stream in a completely trustless manner. For more details refer to the [Ceramic specification](https://github.com/ceramicnetwork/ceramic/blob/master/SPECIFICATION.md?ref=blog.ceramic.network).

**IDX** is a decentralized identity protocol built on top of Ceramic which makes it easy to associate data to a user, discover data a user has created, and build user-centric applications. You can think of IDX as a decentralized user table. Each user has their own _index_ which is a map from _definitions_ to _records_. Definitions are globally-defined descriptions of data created by developers. Each user has their own individual record for each definition which stores their content. For more information have a look at the [IDX developer documentation](https://developers.idx.xyz/learn/overview/?ref=blog.ceramic.network).

## System overview

The proposed conviction voting system is based on an ERC20 token that is periodically snapshotted. This means that the token balances of all users are not updated continuously but instead on a set interval, e.g. twice a day. Additionally, users can easily change their voting preferences at any time.

There are three main system components:

1. **User-created content** including: 1) proposal documents which contain information for a given proposal, and 2) conviction documents where users set their preferences among all live proposals. Both proposal and conviction documents are stored as Ceramic TileDocuments.
2. A **snapshot service** that takes snapshots of the balances of all users of a particular ERC20 token, calculates the total conviction weight for all proposals from users' conviction documents, and saves them into a conviction state document.
3. An **oracle system** that resolves passed proposals on-chain when the conviction state document has sufficient conviction weight for any given proposal.

## User-created content

### Proposal document

Any user can create a _proposal document_ when they want to request funds for a project. This document could contain any amount of information, but most important to be included is: `context` the [caip-19 asset id](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-19.md?ref=blog.ceramic.network) (ERC20 token address) that is used for the conviction voting, `beneficiary` the receiver of the funds if the proposal passes, `amount` the amount of funds to send if the proposal passes.

_Example content_

This example is a proposal to get some funding for a project. Other proposals might include executing a transaction with call data, setting a protocol parameter, or updating some organizational document.

```js

```

Copy

[Proposal document schema in CIP-87](https://github.com/ceramicnetwork/CIP/issues/87?ref=blog.ceramic.network)

### Convictions document

Each participant in the conviction voting system creates their own _convictions document_ when they first interact with the conviction voting dapp. This document contains the convictions the user has assigned to various proposals as a fraction of their entire token holdings. Every time they change their preference the underlying Ceramic document gets updated, signed, and eventually anchored on-chain.

A conviction voting dapp would create a definition as defined in [CIP-87](https://github.com/ceramicnetwork/CIP/issues/87?ref=blog.ceramic.network) and each user would store a convictions document as a record in their IDX.

_Example content_

In this example we see a single user's convictions document. They have created `proposal2` and they have allocated different fractions of their token holdings to proposal 1, 2, and 3.

```js

```

Copy

[Preference document schema in CIP-87](https://github.com/ceramicnetwork/CIP/issues/87?ref=blog.ceramic.network)

## Snapshot service

The snapshot service performs the task of periodically taking a snapshot of the balances of all token holders of the particular ERC20 being used. Using this information together with individual users' conviction documents, it [calculates the total conviction](https://github.com/1Hive/conviction-voting-cadcad/blob/master/algorithm_overview.ipynb?ref=blog.ceramic.network) and writes it to a _conviction state document._ This service is not trusted since anyone could compute the same conviction state by simply grabbing the data from the blockchain. The service executes at a set time interval, for example twice a day.

### Syncing data & performing calculations

Since we are not restricted to calculate the conviction score for all proposals on-chain we can simply use the discrete version of the conviction voting algorithm which can be found at [1Hive/conviction-voting-cadcad](https://github.com/1Hive/conviction-voting-cadcad/blob/master/algorithm_overview.ipynb?ref=blog.ceramic.network). On every discrete time interval the snapshot service grabs all token holders and their balances from the blockchain (e.g. using TheGraph). The address of each token holder is used to look up their individual IDX document which should contain their _convictions document_. The total conviction _y\_t+1_ can now be calculated for each proposal using the formula in _Figure 1_.

Figure 1: How to calculate the total conviction for each proposal j. Source: [https://github.com/1Hive/conviction-voting-cadcad/blob/master/algorithm_overview.ipynb](https://github.com/1Hive/conviction-voting-cadcad/blob/master/algorithm_overview.ipynb?ref=blog.ceramic.network)

Once total conviction for each proposal is calculated, the snapshot service also calculates the trigger function for each proposal. Finally the service updates the _conviction state document_ with the new state.

### Conviction state document

The conviction state document stores the full state of the conviction voting system. It is created and updated by the snapshot service. It contains two main arrays as well as supply information:

- `participants` \- all token holders, their current token balance, and the latest CommitID of their _convictions document_ at the time the snapshot was made.
- `proposals` \- all active proposals and their total conviction which has been calculated by the snapshot service.
- `supply` \- the total supply of the ERC20 token that is used for governance.

_Example content_

In this example we see that there are two participants who have a token balance and have created their own convictions documents. We also see that there are two active proposals, both of which have not yet been triggered, and have different levels of total conviction.

```js

```

Copy

[Conviction state document schema in CIP-87](https://github.com/ceramicnetwork/CIP/issues/87?ref=blog.ceramic.network)

## Oracle system

Once we have the conviction state document it's trivial to check the [trigger function](https://nbviewer.jupyter.org/github/BlockScience/Aragon_Conviction_Voting/blob/master/models/v3/Trigger_Function_Explanation.ipynb?ref=blog.ceramic.network) for any particular proposal. When a proposal has sufficient weight an oracle service (e.g. Chainlink) can be triggered to submit the data of the passed proposal on-chain. This would send the requested funds to the beneficiary in the proposal. It's also possible to use conviction voting to set smart contract parameters or proposal ranking (not execution). In these cases we would calculate a dynamic average instead of using a _trigger function_.

### Executing proposals on-chain

In order to execute the transaction on-chain we can use an oracle system to get the relevant state from the _conviction state document_ on-chain if a proposal has been triggered. Ideally this would be a set of oracles that can independently verify the state of this document before it's committed on-chain. However, in many cases it might be sufficient to use a simpler oracle system such as Chainlink to simply fetch the state of the document from the Ceramic gateway. The main data that needs to make it on-chain is `beneficiary` and `amount`.

## Notes on security

### Snapshot trust

The main point of trust in this system is the snapshot service. While anyone can independently verify that it has performed the proper calculations, this might not always happen. When implementing this CV system in production there likely needs to be some additional checks and balances that enable the snapshot service to be replaced. Alternatively a system may choose to require multiple snapshot service providers that are operated by independent parties.

### Proposal manipulation

The _proposal document_ could be updated to request a larger `amount` of funds after it has already started getting a large amount of conviction. In order to mitigate this attack, the snapshot service might require users to reconfirm their conviction for the proposal, without losing the time staked, before it is triggered.

### Convictions reorg attack

Since Ceramic TileDocuments currently rely on the "earliest anchor wins" conflict resolution method, a user could perform a [data withholding attack](https://github.com/ceramicnetwork/ceramic/blob/master/SPECIFICATION.md?ref=blog.ceramic.network#data-withholding-attacks) where their conviction would be counted twice. The attack would involve the user first updating their preference document to proposal A and anchoring it, but withholding this data by not submitting it to the Ceramic network. Then they would set their preference doc to proposal B and publicly submit this to the network. Once proposal B has been passed, they would publish their data about proposal A which would invalidate their conviction on proposal B (because A was anchored earlier) and it would look as if they have staked their tokens on proposal A for a long period of time. This entire problem is solved by the fact that the snapshot service sets the _CommitID_ of the user's preference doc in the snapshot document. So if a user cheats like this it would be simple to see that they have double voted and all of their votes would be invalidated from that point in time.

## Alternative implementations

IDX can be used to store any type of user-related data such as verifications for social accounts (Twitter, Github, Discord, Discourse, ...), a BrightID score, or any other similar information. This flexibility makes it possible to easily experiment with quadratic voting where accounts that are less likely to be sybils can influence the vote more.

Using an oracle to trigger actions on-chain would be ideal, but as a minimum viable product it might be simpler to just use the off-chain voting system as a way to generate signal. A trusted multi-sig can then be used to execute on-chain actions, similar to how [snapshot.page](http://snapshot.page/?ref=blog.ceramic.network) is used.

## Get involved!

This article outlines a basic framework for how off-chain conviction voting systems can be built, but there are still many details that need to be solved. If you're interested in contributing to this work, reach out in the [Ceramic Discord](https://chat.ceramic.network/?ref=blog.ceramic.network) or just go ahead and build it 🦍:

- Bounty 🤑: [Build a proof of concept off-chain conviction voting system](https://github.com/ceramicnetwork/ceramic/issues/48?ref=blog.ceramic.network) (during Gitcoin Grants Round 9)
- Specification ✅: [CIP-87: Conviction Voting Template](https://github.com/ceramicnetwork/CIP/issues/87?ref=blog.ceramic.network)

## Additional resources

- [Conviction voting UX discussion](https://github.com/1Hive/conviction-voting-app/issues/52?ref=blog.ceramic.network)
- [Twitter thread on the CV cadCAD model](https://twitter.com/commonsstack/status/1309211776425365510?ref=blog.ceramic.network)
- [Conviction voting algorithm](https://github.com/1Hive/conviction-voting-cadcad/blob/master/algorithm_overview.ipynb?ref=blog.ceramic.network)
