-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* init * . * start tests * more test updates * check locked * typo * typo * pubkey * rn * answer comments
- Loading branch information
Showing
31 changed files
with
2,605 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# | ||
# Docker image to generate deterministic, verifiable builds of Anchor programs. | ||
# This must be run *after* a given ANCHOR_CLI version is published and a git tag | ||
# is released on GitHub. | ||
# | ||
|
||
FROM ubuntu:22.04 | ||
|
||
ARG DEBIAN_FRONTEND=noninteractive | ||
|
||
ARG SOLANA_CLI="1.14.7" | ||
ARG ANCHOR_CLI="0.27.0" | ||
ARG NODE_VERSION="v18.16.0" | ||
|
||
ENV HOME="/root" | ||
ENV PATH="${HOME}/.cargo/bin:${PATH}" | ||
ENV PATH="${HOME}/.local/share/solana/install/active_release/bin:${PATH}" | ||
ENV PATH="${HOME}/.nvm/versions/node/${NODE_VERSION}/bin:${PATH}" | ||
|
||
# Install base utilities. | ||
RUN mkdir -p /workdir && mkdir -p /tmp && \ | ||
apt-get update -qq && apt-get upgrade -qq && apt-get install -qq \ | ||
build-essential git curl wget jq pkg-config python3-pip \ | ||
libssl-dev libudev-dev | ||
|
||
RUN wget http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb | ||
RUN dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb | ||
|
||
# Install rust. | ||
RUN curl "https://sh.rustup.rs" -sfo rustup.sh && \ | ||
sh rustup.sh -y && \ | ||
rustup component add rustfmt clippy | ||
|
||
# Install node / npm / yarn. | ||
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash | ||
ENV NVM_DIR="${HOME}/.nvm" | ||
RUN . $NVM_DIR/nvm.sh && \ | ||
nvm install ${NODE_VERSION} && \ | ||
nvm use ${NODE_VERSION} && \ | ||
nvm alias default node && \ | ||
npm install -g yarn && \ | ||
yarn add ts-mocha | ||
|
||
# Install Solana tools. | ||
RUN sh -c "$(curl -sSfL https://release.solana.com/v${SOLANA_CLI}/install)" | ||
|
||
# Install anchor. | ||
RUN cargo install --git https://github.com/coral-xyz/anchor avm --locked --force | ||
RUN avm install ${ANCHOR_CLI} && avm use ${ANCHOR_CLI} | ||
|
||
WORKDIR /workdir | ||
#be sure to add `/root/.avm/bin` to your PATH to be able to run the installed binaries |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"build": { "dockerfile": "Dockerfile" } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"build": { "dockerfile": "Dockerfile" } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
[package] | ||
name = "gpl-token-haver" | ||
version = "0.0.1" | ||
description = "SPL Governance plugin granting governance power based on the nonzero presence of locked tokens" | ||
license = "Apache-2.0" | ||
edition = "2018" | ||
|
||
[lib] | ||
crate-type = ["cdylib", "lib"] | ||
name = "gpl_token_haver" | ||
|
||
[features] | ||
no-entrypoint = [] | ||
no-idl = [] | ||
no-log-ix-name = [] | ||
cpi = ["no-entrypoint"] | ||
default = [] | ||
|
||
[dependencies] | ||
arrayref = "0.3.6" | ||
anchor-lang = { version = "0.26.0" } | ||
anchor-spl = "0.26.0" | ||
solana-program = "1.14.16" | ||
spl-governance = { version = "3.1.1", features = ["no-entrypoint"] } | ||
spl-governance-tools= "0.1.3" | ||
spl-token = { version = "3.3", features = [ "no-entrypoint" ] } | ||
|
||
[dev-dependencies] | ||
borsh = "0.9.1" | ||
solana-sdk = "1.14.16" | ||
solana-program-test = "1.14.16" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[target.bpfel-unknown-unknown.dependencies.std] | ||
features = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
This plugin checks for the presence of nonzero tokens from certain mints in the user's wallet. | ||
|
||
### You would use this if: | ||
|
||
- You want voting power to be based on having an _indefinitely locked_ token, but not proportional to the amount of the token | ||
- You don't want to use a Membership (for UX reasons) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use anchor_lang::prelude::*; | ||
|
||
#[error_code] | ||
pub enum TokenHaverError { | ||
#[msg("Invalid Realm Authority")] | ||
InvalidRealmAuthority, | ||
|
||
#[msg("Invalid Realm for Registrar")] | ||
InvalidRealmForRegistrar, | ||
|
||
#[msg("Invalid VoterWeightRecord Realm")] | ||
InvalidVoterWeightRecordRealm, | ||
|
||
#[msg("Invalid VoterWeightRecord Mint")] | ||
InvalidVoterWeightRecordMint, | ||
|
||
#[msg("Governing TokenOwner must match")] | ||
GoverningTokenOwnerMustMatch, | ||
|
||
#[msg("All token accounts must be owned by the governing token owner")] | ||
TokenAccountWrongOwner, | ||
|
||
#[msg("All token accounts' mints must be included in the registrar")] | ||
TokenAccountWrongMint, | ||
|
||
#[msg("All token accounts' mints must be included in the registrar")] | ||
TokenAccountNotLocked, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
use crate::error::TokenHaverError; | ||
use crate::state::*; | ||
use anchor_lang::system_program::Transfer; | ||
use anchor_lang::{prelude::*, system_program}; | ||
use spl_governance::state::realm; | ||
|
||
/// Configures mints for Registrar | ||
#[derive(Accounts)] | ||
#[instruction(mints: Vec<Pubkey>)] | ||
pub struct ConfigureMints<'info> { | ||
/// The Registrar for the given realm and governing_token_mint | ||
#[account(mut)] | ||
pub registrar: Account<'info, Registrar>, | ||
|
||
#[account( | ||
address = registrar.realm @ TokenHaverError::InvalidRealmForRegistrar, | ||
owner = registrar.governance_program_id | ||
)] | ||
/// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id | ||
pub realm: UncheckedAccount<'info>, | ||
|
||
// will pay in the event of a resize | ||
pub payer: Signer<'info>, | ||
|
||
/// Authority of the Realm must sign and match realm.authority | ||
pub realm_authority: Signer<'info>, | ||
|
||
pub system_program: Program<'info, System>, | ||
} | ||
|
||
pub fn configure_mints(ctx: Context<ConfigureMints>, mints: Vec<Pubkey>) -> Result<()> { | ||
let new_size = Registrar::get_space(mints.len() as u8); | ||
|
||
let rent = Rent::get()?; | ||
let new_minimum_balance = rent.minimum_balance(new_size); | ||
|
||
let lamports_diff = | ||
new_minimum_balance.saturating_sub(ctx.accounts.registrar.to_account_info().lamports()); | ||
|
||
// if lamports_diff is positive, we need to fund the account | ||
if lamports_diff > 0 { | ||
// Create a CPI context for the transfer | ||
let cpi_accounts = Transfer { | ||
from: ctx.accounts.payer.to_account_info().clone(), | ||
to: ctx.accounts.registrar.to_account_info().clone(), | ||
}; | ||
|
||
let cpi_program = ctx.accounts.system_program.to_account_info(); | ||
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); | ||
|
||
// Perform the transfer | ||
system_program::transfer(cpi_ctx, lamports_diff)?; | ||
} | ||
|
||
let registrar = &mut ctx.accounts.registrar; | ||
registrar.to_account_info().realloc(new_size, false)?; | ||
|
||
registrar.mints = mints; | ||
|
||
let realm = realm::get_realm_data_for_governing_token_mint( | ||
®istrar.governance_program_id, | ||
&ctx.accounts.realm, | ||
®istrar.governing_token_mint, | ||
)?; | ||
|
||
require_eq!( | ||
realm.authority.unwrap(), | ||
ctx.accounts.realm_authority.key(), | ||
TokenHaverError::InvalidRealmAuthority | ||
); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use crate::error::TokenHaverError; | ||
use crate::state::*; | ||
use anchor_lang::prelude::*; | ||
use anchor_spl::token::Mint; | ||
use spl_governance::state::realm; | ||
|
||
/// Creates Registrar storing Realm Voter configuration for spl-governance Realm | ||
/// This instruction should only be executed once per realm/governing_token_mint to create the account | ||
#[derive(Accounts)] | ||
#[instruction(mints: Vec<Pubkey>)] | ||
pub struct CreateRegistrar<'info> { | ||
/// The Realm Voter Registrar | ||
/// There can only be a single registrar per governance Realm and governing mint of the Realm | ||
#[account( | ||
init, | ||
seeds = [b"registrar".as_ref(),realm.key().as_ref(), governing_token_mint.key().as_ref()], | ||
bump, | ||
payer = payer, | ||
space = Registrar::get_space(mints.len() as u8), | ||
)] | ||
pub registrar: Account<'info, Registrar>, | ||
|
||
/// The program id of the spl-governance program the realm belongs to | ||
/// CHECK: Can be any instance of spl-governance and it's not known at the compilation time | ||
#[account(executable)] | ||
pub governance_program_id: UncheckedAccount<'info>, | ||
|
||
/// An spl-governance Realm | ||
/// | ||
/// Realm is validated in the instruction: | ||
/// - Realm is owned by the governance_program_id | ||
/// - governing_token_mint must be the community or council mint | ||
/// - realm_authority is realm.authority | ||
/// CHECK: Owned by spl-governance instance specified in governance_program_id | ||
#[account(owner = governance_program_id.key())] | ||
pub realm: UncheckedAccount<'info>, | ||
|
||
/// Either the realm community mint or the council mint. | ||
/// It must match Realm.community_mint or Realm.config.council_mint | ||
/// | ||
/// Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity | ||
/// for the voting population and the tokens of that are no longer used | ||
pub governing_token_mint: Account<'info, Mint>, | ||
|
||
/// realm_authority must sign and match Realm.authority | ||
pub realm_authority: Signer<'info>, | ||
|
||
#[account(mut)] | ||
pub payer: Signer<'info>, | ||
|
||
pub system_program: Program<'info, System>, | ||
} | ||
|
||
/// Creates a new Registrar which stores Realms voter configuration for the given Realm | ||
/// | ||
/// To use the registrar, call ConfigureGovernanceProgram to register spl-governance instance which will be | ||
/// used for governance | ||
/// | ||
pub fn create_registrar(ctx: Context<CreateRegistrar>, mints: Vec<Pubkey>) -> Result<()> { | ||
let registrar = &mut ctx.accounts.registrar; | ||
**registrar = Registrar { | ||
governance_program_id: ctx.accounts.governance_program_id.key(), | ||
realm: ctx.accounts.realm.key(), | ||
governing_token_mint: ctx.accounts.governing_token_mint.key(), | ||
mints, | ||
}; | ||
|
||
// Verify that realm_authority is the expected authority of the Realm | ||
// and that the mint matches one of the realm mints too | ||
let realm = realm::get_realm_data_for_governing_token_mint( | ||
®istrar.governance_program_id, | ||
&ctx.accounts.realm, | ||
®istrar.governing_token_mint, | ||
)?; | ||
|
||
require_eq!( | ||
realm.authority.unwrap(), | ||
ctx.accounts.realm_authority.key(), | ||
TokenHaverError::InvalidRealmAuthority | ||
); | ||
|
||
Ok(()) | ||
} |
46 changes: 46 additions & 0 deletions
46
programs/token-haver/src/instructions/create_voter_weight_record.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
use crate::state::*; | ||
use anchor_lang::prelude::*; | ||
|
||
/// Creates VoterWeightRecord used by spl-gov | ||
/// This instruction should only be executed once per realm/governing_token_mint/governing_token_owner | ||
/// to create the account | ||
#[derive(Accounts)] | ||
#[instruction(governing_token_owner: Pubkey)] | ||
pub struct CreateVoterWeightRecord<'info> { | ||
// The Registrar the VoterWeightRecord account belongs to | ||
pub registrar: Account<'info, Registrar>, | ||
|
||
#[account( | ||
init, | ||
seeds = [ b"voter-weight-record".as_ref(), | ||
registrar.realm.key().as_ref(), | ||
registrar.governing_token_mint.key().as_ref(), | ||
governing_token_owner.as_ref()], | ||
bump, | ||
payer = payer, | ||
space = VoterWeightRecord::get_space() | ||
)] | ||
pub voter_weight_record: Account<'info, VoterWeightRecord>, | ||
|
||
#[account(mut)] | ||
pub payer: Signer<'info>, | ||
|
||
pub system_program: Program<'info, System>, | ||
} | ||
|
||
pub fn create_voter_weight_record( | ||
ctx: Context<CreateVoterWeightRecord>, | ||
governing_token_owner: Pubkey, | ||
) -> Result<()> { | ||
let voter_weight_record = &mut ctx.accounts.voter_weight_record; | ||
let registrar = &ctx.accounts.registrar; | ||
|
||
voter_weight_record.realm = registrar.realm.key(); | ||
voter_weight_record.governing_token_mint = registrar.governing_token_mint.key(); | ||
voter_weight_record.governing_token_owner = governing_token_owner; | ||
|
||
// Set expiry to expired | ||
voter_weight_record.voter_weight_expiry = Some(0); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
pub use create_registrar::*; | ||
mod create_registrar; | ||
|
||
pub use create_voter_weight_record::*; | ||
mod create_voter_weight_record; | ||
|
||
pub use update_voter_weight_record::*; | ||
mod update_voter_weight_record; | ||
|
||
pub use configure_mints::*; | ||
mod configure_mints; |
Oops, something went wrong.