Create and write vote weight records
This commit is contained in:
parent
f00531fb7f
commit
eaf6890146
|
@ -1,4 +1,3 @@
|
||||||
use crate::account::*;
|
|
||||||
use crate::context::*;
|
use crate::context::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use anchor_lang::prelude::*;
|
use anchor_lang::prelude::*;
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub const MAX_DAYS_LOCKED: u64 = 2555;
|
||||||
pub struct Registrar {
|
pub struct Registrar {
|
||||||
pub authority: Pubkey,
|
pub authority: Pubkey,
|
||||||
pub realm: Pubkey,
|
pub realm: Pubkey,
|
||||||
|
pub realm_community_mint: Pubkey,
|
||||||
pub warmup_secs: i64,
|
pub warmup_secs: i64,
|
||||||
pub bump: u8,
|
pub bump: u8,
|
||||||
// The length should be adjusted for one's use case.
|
// The length should be adjusted for one's use case.
|
||||||
|
@ -32,6 +33,7 @@ pub struct Voter {
|
||||||
pub authority: Pubkey,
|
pub authority: Pubkey,
|
||||||
pub registrar: Pubkey,
|
pub registrar: Pubkey,
|
||||||
pub voter_bump: u8,
|
pub voter_bump: u8,
|
||||||
|
pub voter_weight_record_bump: u8,
|
||||||
pub deposits: [DepositEntry; 32],
|
pub deposits: [DepositEntry; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +288,7 @@ impl Lockup {
|
||||||
|
|
||||||
u64::try_from({
|
u64::try_from({
|
||||||
let secs_elapsed = curr_ts.checked_sub(self.start_ts).unwrap();
|
let secs_elapsed = curr_ts.checked_sub(self.start_ts).unwrap();
|
||||||
secs_elapsed.checked_sub(SECS_PER_DAY).unwrap()
|
secs_elapsed.checked_div(SECS_PER_DAY).unwrap()
|
||||||
})
|
})
|
||||||
.map_err(|_| ErrorCode::UnableToConvert.into())
|
.map_err(|_| ErrorCode::UnableToConvert.into())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ use anchor_spl::associated_token::AssociatedToken;
|
||||||
use anchor_spl::token::{self, Mint, Token, TokenAccount};
|
use anchor_spl::token::{self, Mint, Token, TokenAccount};
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
||||||
|
pub const VOTER_WEIGHT_RECORD: [u8; 19] = *b"voter-weight-record";
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
#[instruction(warmup_secs: i64, registrar_bump: u8)]
|
#[instruction(warmup_secs: i64, registrar_bump: u8)]
|
||||||
pub struct CreateRegistrar<'info> {
|
pub struct CreateRegistrar<'info> {
|
||||||
|
@ -15,7 +17,10 @@ pub struct CreateRegistrar<'info> {
|
||||||
space = 8 + size_of::<Registrar>()
|
space = 8 + size_of::<Registrar>()
|
||||||
)]
|
)]
|
||||||
pub registrar: AccountLoader<'info, Registrar>,
|
pub registrar: AccountLoader<'info, Registrar>,
|
||||||
|
// Unsafe and untrusted. This instruction needs to be invoked immediatley
|
||||||
|
// after the realm is created.
|
||||||
pub realm: UncheckedAccount<'info>,
|
pub realm: UncheckedAccount<'info>,
|
||||||
|
pub realm_community_mint: Account<'info, Mint>,
|
||||||
pub authority: UncheckedAccount<'info>,
|
pub authority: UncheckedAccount<'info>,
|
||||||
pub payer: Signer<'info>,
|
pub payer: Signer<'info>,
|
||||||
pub system_program: Program<'info, System>,
|
pub system_program: Program<'info, System>,
|
||||||
|
@ -24,7 +29,7 @@ pub struct CreateRegistrar<'info> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
#[instruction(voter_bump: u8)]
|
#[instruction(voter_bump: u8, voter_weight_record_bump: u8)]
|
||||||
pub struct CreateVoter<'info> {
|
pub struct CreateVoter<'info> {
|
||||||
#[account(
|
#[account(
|
||||||
init,
|
init,
|
||||||
|
@ -34,8 +39,17 @@ pub struct CreateVoter<'info> {
|
||||||
space = 8 + size_of::<Voter>(),
|
space = 8 + size_of::<Voter>(),
|
||||||
)]
|
)]
|
||||||
pub voter: AccountLoader<'info, Voter>,
|
pub voter: AccountLoader<'info, Voter>,
|
||||||
|
#[account(
|
||||||
|
init
|
||||||
|
, seeds = [VOTER_WEIGHT_RECORD.as_ref(), registrar.key().as_ref(), authority.key().as_ref()],
|
||||||
|
bump = voter_weight_record_bump,
|
||||||
|
payer = payer,
|
||||||
|
space = 150,
|
||||||
|
)]
|
||||||
|
pub voter_weight_record: Account<'info, VoterWeightRecord>,
|
||||||
pub registrar: AccountLoader<'info, Registrar>,
|
pub registrar: AccountLoader<'info, Registrar>,
|
||||||
pub authority: Signer<'info>,
|
pub authority: Signer<'info>,
|
||||||
|
pub payer: Signer<'info>,
|
||||||
pub token_program: Program<'info, Token>,
|
pub token_program: Program<'info, Token>,
|
||||||
pub associated_token_program: Program<'info, AssociatedToken>,
|
pub associated_token_program: Program<'info, AssociatedToken>,
|
||||||
pub system_program: Program<'info, System>,
|
pub system_program: Program<'info, System>,
|
||||||
|
@ -237,9 +251,9 @@ pub struct UpdateSchedule<'info> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
pub struct DecayVotingPower<'info> {
|
pub struct UpdateVoterWeightRecord<'info> {
|
||||||
#[account(
|
#[account(
|
||||||
seeds = [vote_weight_record.realm.as_ref()],
|
seeds = [voter_weight_record.realm.as_ref()],
|
||||||
bump = registrar.load()?.bump,
|
bump = registrar.load()?.bump,
|
||||||
)]
|
)]
|
||||||
pub registrar: AccountLoader<'info, Registrar>,
|
pub registrar: AccountLoader<'info, Registrar>,
|
||||||
|
@ -250,10 +264,14 @@ pub struct DecayVotingPower<'info> {
|
||||||
pub voter: AccountLoader<'info, Voter>,
|
pub voter: AccountLoader<'info, Voter>,
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
constraint = vote_weight_record.governing_token_owner == voter.load()?.authority,
|
seeds = [VOTER_WEIGHT_RECORD.as_ref(), registrar.key().as_ref(), authority.key().as_ref()],
|
||||||
|
bump = voter.load()?.voter_weight_record_bump,
|
||||||
|
constraint = voter_weight_record.realm == registrar.load()?.realm,
|
||||||
|
constraint = voter_weight_record.governing_token_owner == voter.load()?.authority,
|
||||||
)]
|
)]
|
||||||
pub vote_weight_record: Account<'info, VoterWeightRecord>,
|
pub voter_weight_record: Account<'info, VoterWeightRecord>,
|
||||||
pub authority: Signer<'info>,
|
pub authority: Signer<'info>,
|
||||||
|
pub system_program: Program<'info, System>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
|
|
|
@ -4,6 +4,7 @@ use anchor_lang::prelude::*;
|
||||||
use anchor_spl::token;
|
use anchor_spl::token;
|
||||||
use context::*;
|
use context::*;
|
||||||
use error::*;
|
use error::*;
|
||||||
|
use spl_governance::addins::voter_weight::VoterWeightAccountType;
|
||||||
|
|
||||||
mod access_control;
|
mod access_control;
|
||||||
mod account;
|
mod account;
|
||||||
|
@ -71,6 +72,7 @@ pub mod governance_registry {
|
||||||
let registrar = &mut ctx.accounts.registrar.load_init()?;
|
let registrar = &mut ctx.accounts.registrar.load_init()?;
|
||||||
registrar.bump = registrar_bump;
|
registrar.bump = registrar_bump;
|
||||||
registrar.realm = ctx.accounts.realm.key();
|
registrar.realm = ctx.accounts.realm.key();
|
||||||
|
registrar.realm_community_mint = ctx.accounts.realm_community_mint.key();
|
||||||
registrar.authority = ctx.accounts.authority.key();
|
registrar.authority = ctx.accounts.authority.key();
|
||||||
registrar.warmup_secs = warmup_secs;
|
registrar.warmup_secs = warmup_secs;
|
||||||
|
|
||||||
|
@ -97,12 +99,28 @@ pub mod governance_registry {
|
||||||
|
|
||||||
/// Creates a new voter account. There can only be a single voter per
|
/// Creates a new voter account. There can only be a single voter per
|
||||||
/// user wallet.
|
/// user wallet.
|
||||||
pub fn create_voter(ctx: Context<CreateVoter>, voter_bump: u8) -> Result<()> {
|
pub fn create_voter(
|
||||||
|
ctx: Context<CreateVoter>,
|
||||||
|
voter_bump: u8,
|
||||||
|
voter_weight_record_bump: u8,
|
||||||
|
) -> Result<()> {
|
||||||
|
// Load accounts.
|
||||||
|
let registrar = &ctx.accounts.registrar.load()?;
|
||||||
let voter = &mut ctx.accounts.voter.load_init()?;
|
let voter = &mut ctx.accounts.voter.load_init()?;
|
||||||
|
let voter_weight_record = &mut ctx.accounts.voter_weight_record;
|
||||||
|
|
||||||
|
// Init the voter.
|
||||||
voter.voter_bump = voter_bump;
|
voter.voter_bump = voter_bump;
|
||||||
|
voter.voter_weight_record_bump = voter_weight_record_bump;
|
||||||
voter.authority = ctx.accounts.authority.key();
|
voter.authority = ctx.accounts.authority.key();
|
||||||
voter.registrar = ctx.accounts.registrar.key();
|
voter.registrar = ctx.accounts.registrar.key();
|
||||||
|
|
||||||
|
// Init the voter weight record.
|
||||||
|
voter_weight_record.account_type = VoterWeightAccountType::VoterWeightRecord;
|
||||||
|
voter_weight_record.realm = registrar.realm;
|
||||||
|
voter_weight_record.governing_token_mint = registrar.realm_community_mint;
|
||||||
|
voter_weight_record.governing_token_owner = ctx.accounts.authority.key();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,11 +324,12 @@ pub mod governance_registry {
|
||||||
///
|
///
|
||||||
/// This "revise" instruction should be called in the same transaction,
|
/// This "revise" instruction should be called in the same transaction,
|
||||||
/// immediately before voting.
|
/// immediately before voting.
|
||||||
pub fn decay_voting_power(ctx: Context<DecayVotingPower>) -> Result<()> {
|
pub fn update_voter_weight_record(ctx: Context<UpdateVoterWeightRecord>) -> Result<()> {
|
||||||
let voter = ctx.accounts.voter.load()?;
|
let voter = ctx.accounts.voter.load()?;
|
||||||
let record = &mut ctx.accounts.vote_weight_record;
|
let record = &mut ctx.accounts.voter_weight_record;
|
||||||
record.voter_weight = voter.weight()?;
|
record.voter_weight = voter.weight()?;
|
||||||
record.voter_weight_expiry = Some(Clock::get()?.slot);
|
record.voter_weight_expiry = Some(Clock::get()?.slot);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,14 +35,20 @@ describe("voting-rights", () => {
|
||||||
votingMintA: PublicKey,
|
votingMintA: PublicKey,
|
||||||
votingMintB: PublicKey,
|
votingMintB: PublicKey,
|
||||||
voter: PublicKey,
|
voter: PublicKey,
|
||||||
|
voterWeightRecord: PublicKey,
|
||||||
votingToken: PublicKey,
|
votingToken: PublicKey,
|
||||||
exchangeVaultA: PublicKey,
|
exchangeVaultA: PublicKey,
|
||||||
exchangeVaultB: PublicKey;
|
exchangeVaultB: PublicKey;
|
||||||
let registrarBump: number,
|
let registrarBump: number,
|
||||||
votingMintBumpA: number,
|
votingMintBumpA: number,
|
||||||
votingMintBumpB: number,
|
votingMintBumpB: number,
|
||||||
voterBump: number;
|
voterBump: number,
|
||||||
let mintA: PublicKey, mintB: PublicKey, godA: PublicKey, godB: PublicKey;
|
voterWeightRecordBump: number;
|
||||||
|
let mintA: PublicKey,
|
||||||
|
mintB: PublicKey,
|
||||||
|
godA: PublicKey,
|
||||||
|
godB: PublicKey,
|
||||||
|
realmCommunityMint: PublicKey;
|
||||||
let tokenAClient: Token,
|
let tokenAClient: Token,
|
||||||
tokenBClient: Token,
|
tokenBClient: Token,
|
||||||
votingTokenClientA: Token,
|
votingTokenClientA: Token,
|
||||||
|
@ -66,6 +72,7 @@ describe("voting-rights", () => {
|
||||||
mintB = _mintB;
|
mintB = _mintB;
|
||||||
godA = _godA;
|
godA = _godA;
|
||||||
godB = _godB;
|
godB = _godB;
|
||||||
|
realmCommunityMint = mintA;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Creates PDAs", async () => {
|
it("Creates PDAs", async () => {
|
||||||
|
@ -85,6 +92,15 @@ describe("voting-rights", () => {
|
||||||
[_registrar.toBuffer(), program.provider.wallet.publicKey.toBuffer()],
|
[_registrar.toBuffer(), program.provider.wallet.publicKey.toBuffer()],
|
||||||
program.programId
|
program.programId
|
||||||
);
|
);
|
||||||
|
const [_voterWeightRecord, _voterWeightRecordBump] =
|
||||||
|
await PublicKey.findProgramAddress(
|
||||||
|
[
|
||||||
|
anchor.utils.bytes.utf8.encode("voter-weight-record"),
|
||||||
|
_registrar.toBuffer(),
|
||||||
|
program.provider.wallet.publicKey.toBuffer(),
|
||||||
|
],
|
||||||
|
program.programId
|
||||||
|
);
|
||||||
votingToken = await Token.getAssociatedTokenAddress(
|
votingToken = await Token.getAssociatedTokenAddress(
|
||||||
associatedTokenProgram,
|
associatedTokenProgram,
|
||||||
tokenProgram,
|
tokenProgram,
|
||||||
|
@ -115,6 +131,8 @@ describe("voting-rights", () => {
|
||||||
votingMintBumpA = _votingMintBumpA;
|
votingMintBumpA = _votingMintBumpA;
|
||||||
votingMintBumpB = _votingMintBumpB;
|
votingMintBumpB = _votingMintBumpB;
|
||||||
voterBump = _voterBump;
|
voterBump = _voterBump;
|
||||||
|
voterWeightRecord = _voterWeightRecord;
|
||||||
|
voterWeightRecordBump = _voterWeightRecordBump;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Creates token clients", async () => {
|
it("Creates token clients", async () => {
|
||||||
|
@ -149,21 +167,18 @@ describe("voting-rights", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Initializes a registrar", async () => {
|
it("Initializes a registrar", async () => {
|
||||||
await program.rpc.createRegistrar(
|
await program.rpc.createRegistrar(new BN(0), registrarBump, {
|
||||||
new BN(0),
|
|
||||||
registrarBump,
|
|
||||||
{
|
|
||||||
accounts: {
|
accounts: {
|
||||||
registrar,
|
registrar,
|
||||||
realm,
|
realm,
|
||||||
|
realmCommunityMint,
|
||||||
authority: program.provider.wallet.publicKey,
|
authority: program.provider.wallet.publicKey,
|
||||||
payer: program.provider.wallet.publicKey,
|
payer: program.provider.wallet.publicKey,
|
||||||
systemProgram,
|
systemProgram,
|
||||||
tokenProgram,
|
tokenProgram,
|
||||||
rent,
|
rent,
|
||||||
},
|
},
|
||||||
}
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Adds an exchange rate A", async () => {
|
it("Adds an exchange rate A", async () => {
|
||||||
|
@ -209,11 +224,13 @@ describe("voting-rights", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Initializes a voter", async () => {
|
it("Initializes a voter", async () => {
|
||||||
await program.rpc.createVoter(voterBump, {
|
await program.rpc.createVoter(voterBump, voterWeightRecordBump, {
|
||||||
accounts: {
|
accounts: {
|
||||||
voter,
|
voter,
|
||||||
|
voterWeightRecord,
|
||||||
registrar,
|
registrar,
|
||||||
authority: program.provider.wallet.publicKey,
|
authority: program.provider.wallet.publicKey,
|
||||||
|
payer: program.provider.wallet.publicKey,
|
||||||
systemProgram,
|
systemProgram,
|
||||||
associatedTokenProgram,
|
associatedTokenProgram,
|
||||||
tokenProgram,
|
tokenProgram,
|
||||||
|
@ -313,4 +330,16 @@ describe("voting-rights", () => {
|
||||||
assert.ok(deposit.amountDeposited.toNumber() === 10);
|
assert.ok(deposit.amountDeposited.toNumber() === 10);
|
||||||
assert.ok(deposit.rateIdx === 0);
|
assert.ok(deposit.rateIdx === 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Updates a vote weight record", async () => {
|
||||||
|
await program.rpc.updateVoterWeightRecord({
|
||||||
|
accounts: {
|
||||||
|
registrar,
|
||||||
|
voter,
|
||||||
|
voterWeightRecord,
|
||||||
|
authority: program.provider.wallet.publicKey,
|
||||||
|
systemProgram,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue