Voter-stake-registry is a voter weight addin for Solana's spl-governance program.
With the addin enabled, the governance realm authority can:
-
Control which token mints can be used to vote, and at what scaling factor.
That means that tokens from mints other than the governing mint can be used to vote and that their relative weight can be set.
-
Claw back locked tokens from user deposits where the user has enabled it.
This is intended for use with token grants. Users would not enable clawback for normal deposits.
Users can:
-
Deposit and withdraw tokens of the chosen mints to gain voting weight.
When an addin is enabled, the default deposit/withdraw flow of the governing token mints is disabled in spl-governance. The addin adds back the ability to deposit and withdraw without lockup.
-
Lock up tokens with different vesting schedules.
The tokens will only be withdrawable once vested or the lock up has expired. Locked up tokens may have extra voting weight.
-
Use their voting weight to vote on spl-governance proposals.
- Built and developed using - rust stable(
rustc 1.57.0 (f1edd0429 2021-11-29)
) - Run rust based tests -
cargo test-sbf
run-generate-anchor-types.sh
generates latest anchor types file and writes to./voter_stake_registry.ts
- To install the typescript client, do -
yarn add @blockworks-foundation/voter-stake-registry-client
- usage
- Built and developed using - node (
v16.13.1
) - Usage
import { Provider, Wallet } from '@project-serum/anchor';
import { Connection, Keypair } from '@solana/web3.js';
import { VsrClient } from '@blockworks-foundation/voter-stake-registry-client';
async function main() {
const options = Provider.defaultOptions();
const connection = new Connection('https://api.devnet.solana.com', options);
const wallet = new Wallet(Keypair.generate());
const provider = new Provider(connection, wallet, options);
const client = await VsrClient.connect(provider, true);
Users will likely want to compile their own voter-stake-registry and deploy it to an address they control.
Before compiling, look at:
Registrar::voting_mints
: The length of this array defines the number of configurable voting mints. Adjust as needed.
For testing purposes, an instance of voter-stake-registry is deployed on devnet:
voter-stake-registry: 4Q6WW2ouZ6V3iaNm56MTd5n2tnTm4C5fiH8miFHnAFHo
spl-governance master: i7BqPFNUvB7yqwVeCRJHrtZVwRsZZNUJTdBm7Vg2cDb
To start using the addin, make a governance proposal with the spl-governance realm authority to:
- Deploy an instance of the voter-stake-registry.
- Create a registrar for the realm with the
CreateRegistrar
instruction. - Add voting token mints to the registrar by calling the
ConfigureVotingMint
instruction as often as desired. - Call the
SetRealmConfig
instruction on spl-governance to set the voter-weight-addin program id and thereby enable the addin.
-
Call
CreateVoter
on the addin (first time only). Use the same voter_authority that was used for registering with spl-governance. -
Call
CreateDepositEntry
for the voter withLockupKind::None
and the token mint for that tokens are to be deposited. (first time only)This creates a new deposit entry that can be used for depositing and withdrawing funds without lockup.
-
Call
Deposit
for the voter and same deposit entry id to deposit funds. -
To vote, call
UpdateVoterWeightRecord
on the addin and then callCastVote
on spl-governance in the same transaction, passing the voter weight record to both. -
Withdraw funds with
Withdraw
once proposals have resolved.
- Ask the recepient for their desired address.
- Make a proposal to call
Grant
for depositing tokens into a new locked deposit entry for their address. Use a governance that either is the realm authority or the token mint's grant authority. - If necessary, later make a proposal to call
Clawback
on their deposit to retrieve all remaining locked tokens.
Constant maturity deposits are useful when there's a vote weight bonus for locking up tokens: With cliff or daily/monthly vested deposits the remaining lockup period decreases as the time of maturity approaches and thus the vote weight decreases over time as well.
Constant maturity lockup keeps tokens at a fixed maturity. That guarantees a fixed vote weight, but also means they need to be manually transitioned to a different lockup type before they can eventually be withdrawn.
Setting up a constant maturity lockup is easy:
- Create a deposit entry of
Constant
lockup type with the chosen number of days. Deposit
tokens into it.- Use it to vote.
If you want access to the tokens again, you need to start the unlocking process by either
- changing the whole deposit entry to
Cliff
withResetLockup
, or - creating a new
Cliff
deposit entry and transfering some locked tokens from yourConstant
deposit entry over withInternalTransferLocked
.
In both cases you'll need to wait for the cliff to be reached before being able to access the tokens again.
-
Creates a Registrar account for a governance realm.
-
Enables voting with tokens from a mint and sets the exchange rate for vote weight.
-
Create a new voter account for a user.
-
Create a deposit entry on a voter. A deposit entry is where tokens from a voting mint are deposited, and which may optionally have a lockup period and vesting schedule.
Each voter can have multiple deposit entries.
-
Add tokens to a deposit entry.
-
Remove tokens from a deposit entry, either unlocked or vested.
-
Re-lock tokens where the lockup has expired, or increase the duration of the lockup or change the lockup kind.
-
Transfer locked tokens from one deposit entry to another. Useful for splitting off a chunk of a "constant" lockup deposit entry that you want to start the unlock process on.
-
Transfer unlocked tokens from one deposit entry to another. Useful for splitting off a chunk to be locked again in a different deposit entry without having to withdraw and redeposit.
-
Write the current voter weight to the account that spl-governance can read to prepare for voting.
-
Close an empty deposit entry, so it can be reused for a different mint or lockup type.
-
Close an empty voter, reclaiming rent.
-
As the realm authority or mint's grant authority: create a voter (if needed), create a new deposit and fund it. This instruction is intended for use with DAO proposals.
-
As the clawback authority, claim locked tokens from a voter's deposit entry that has opted-in to clawback.
-
Unfinished instruction for telling spl-governance about the total maximum vote weight.
-
Debug instruction for advancing time in tests. Not usable.
This code is currently not free to use while in development.