2021-12-02 07:28:12 -08:00
|
|
|
use crate::error::*;
|
2021-12-03 00:52:48 -08:00
|
|
|
use crate::state::*;
|
2021-12-02 07:28:12 -08:00
|
|
|
use anchor_lang::prelude::*;
|
2021-12-16 23:02:14 -08:00
|
|
|
use anchor_spl::token::Mint;
|
2021-12-02 07:28:12 -08:00
|
|
|
|
2021-12-09 02:58:15 -08:00
|
|
|
// Remaining accounts must be all the token mints that have registered
|
|
|
|
// as voting mints, including the newly registered one.
|
2021-12-02 07:28:12 -08:00
|
|
|
#[derive(Accounts)]
|
2021-12-03 11:36:42 -08:00
|
|
|
pub struct ConfigureVotingMint<'info> {
|
2021-12-02 07:28:12 -08:00
|
|
|
#[account(mut, has_one = realm_authority)]
|
2021-12-08 23:22:22 -08:00
|
|
|
pub registrar: AccountLoader<'info, Registrar>,
|
2021-12-02 07:28:12 -08:00
|
|
|
pub realm_authority: Signer<'info>,
|
|
|
|
|
2021-12-02 10:30:41 -08:00
|
|
|
/// Tokens of this mint will produce vote weight
|
|
|
|
pub mint: Account<'info, Mint>,
|
2022-01-13 06:28:40 -08:00
|
|
|
// This instruction expects that all voting mint addresses, including a
|
|
|
|
// newly registered one, are passed in ctx.remainingAccounts.
|
2021-12-02 07:28:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a new exchange rate for a given mint. This allows a voter to
|
2021-12-02 10:30:41 -08:00
|
|
|
/// deposit the mint in exchange for vote weight. There can only be a single
|
2021-12-02 07:28:12 -08:00
|
|
|
/// exchange rate per mint.
|
|
|
|
///
|
2021-12-09 02:58:15 -08:00
|
|
|
/// * `idx`: index of the rate to be set
|
|
|
|
/// * `digit_shift`: how many digits to shift the native token amount, see below
|
2022-01-25 05:49:23 -08:00
|
|
|
/// * `unlocked_scaled_factor`: vote weight factor for unlocked deposits, in 1/1e9 units
|
2021-12-09 02:58:15 -08:00
|
|
|
/// * `lockup_scaled_factor`: max extra weight for lockups, in 1/1e9 units
|
|
|
|
/// * `lockup_saturation_secs`: lockup duration at which the full vote weight
|
|
|
|
/// bonus is given to locked up deposits
|
2021-12-02 10:30:41 -08:00
|
|
|
///
|
2021-12-09 07:39:06 -08:00
|
|
|
/// This instruction can be called several times for the same mint and index to
|
|
|
|
/// change the voting mint configuration.
|
|
|
|
///
|
2021-12-09 02:58:15 -08:00
|
|
|
/// The vote weight for `amount` of native tokens will be
|
2021-12-02 10:30:41 -08:00
|
|
|
/// ```
|
2021-12-09 02:58:15 -08:00
|
|
|
/// vote_weight =
|
|
|
|
/// amount * 10^(digit_shift)
|
2022-01-25 05:49:23 -08:00
|
|
|
/// * (unlocked_scaled_factor/1e9
|
2021-12-09 02:58:15 -08:00
|
|
|
/// + lockup_duration_factor * lockup_scaled_factor/1e9)
|
2021-12-02 10:30:41 -08:00
|
|
|
/// ```
|
2021-12-09 02:58:15 -08:00
|
|
|
/// where lockup_duration_factor is a value between 0 and 1, depending on how long
|
|
|
|
/// the amount is locked up. It is 1 when the lockup duration is greater or equal
|
|
|
|
/// lockup_saturation_secs.
|
|
|
|
///
|
|
|
|
/// Warning: Choose values that ensure that the vote weight will not overflow the
|
|
|
|
/// u64 limit! There is a check based on the supply of all configured mints, but
|
|
|
|
/// do your own checking too.
|
|
|
|
///
|
2022-01-25 05:49:23 -08:00
|
|
|
/// If you use a single mint, prefer digit_shift=0 and unlocked_scaled_factor +
|
2021-12-09 02:58:15 -08:00
|
|
|
/// lockup_scaled_factor <= 1e9. That way you won't have issues with overflow no
|
|
|
|
/// matter the size of the mint's supply.
|
|
|
|
///
|
|
|
|
/// Digit shifting is particularly useful when using several voting token mints
|
|
|
|
/// that have a different number of decimals. It can be used to align them to
|
|
|
|
/// a common number of decimals.
|
|
|
|
///
|
|
|
|
/// Example: If you have token A with 6 decimals and token B with 9 decimals, you
|
|
|
|
/// could set up:
|
2022-01-25 05:49:23 -08:00
|
|
|
/// * A with digit_shift=0, unlocked_scaled_factor=2e9, lockup_scaled_factor=0
|
|
|
|
/// * B with digit_shift=-3, unlocked_scaled_factor=1e9, lockup_scaled_factor=1e9
|
2021-12-09 02:58:15 -08:00
|
|
|
///
|
|
|
|
/// That would make 1.0 decimaled tokens of A as valuable as 2.0 decimaled tokens
|
|
|
|
/// of B when unlocked. B tokens could be locked up to double their vote weight. As
|
|
|
|
/// long as A's and B's supplies are below 2^63, there could be no overflow.
|
|
|
|
///
|
|
|
|
/// Note that in this example, you need 1000 native B tokens before receiving 1
|
|
|
|
/// unit of vote weight. If the supplies were significantly lower, you could use
|
2022-01-25 05:49:23 -08:00
|
|
|
/// * A with digit_shift=3, unlocked_scaled_factor=2e9, lockup_scaled_factor=0
|
|
|
|
/// * B with digit_shift=0, unlocked_scaled_factor=1e9, lockup_scaled_factor=1e9
|
2021-12-09 02:58:15 -08:00
|
|
|
/// to not lose precision on B tokens.
|
|
|
|
///
|
2021-12-03 11:36:42 -08:00
|
|
|
pub fn configure_voting_mint(
|
|
|
|
ctx: Context<ConfigureVotingMint>,
|
2021-12-02 07:28:12 -08:00
|
|
|
idx: u16,
|
2021-12-09 02:58:15 -08:00
|
|
|
digit_shift: i8,
|
2022-01-25 05:49:23 -08:00
|
|
|
unlocked_scaled_factor: u64,
|
2021-12-09 02:58:15 -08:00
|
|
|
lockup_scaled_factor: u64,
|
|
|
|
lockup_saturation_secs: u64,
|
2021-12-05 07:59:22 -08:00
|
|
|
grant_authority: Option<Pubkey>,
|
2021-12-02 07:28:12 -08:00
|
|
|
) -> Result<()> {
|
2021-12-09 02:58:15 -08:00
|
|
|
require!(lockup_saturation_secs > 0, LockupSaturationMustBePositive);
|
2021-12-08 23:22:22 -08:00
|
|
|
let registrar = &mut ctx.accounts.registrar.load_mut()?;
|
2021-12-09 07:39:06 -08:00
|
|
|
let mint = ctx.accounts.mint.key();
|
|
|
|
let idx = idx as usize;
|
2021-12-03 07:06:44 -08:00
|
|
|
require!(
|
2021-12-09 07:39:06 -08:00
|
|
|
idx < registrar.voting_mints.len(),
|
2021-12-03 11:36:42 -08:00
|
|
|
OutOfBoundsVotingMintConfigIndex
|
2021-12-03 07:06:44 -08:00
|
|
|
);
|
2021-12-09 07:39:06 -08:00
|
|
|
|
2022-01-13 06:28:40 -08:00
|
|
|
// Either it's reconfiguring an existing mint with the correct index,
|
|
|
|
// or configuring a new mint on an unused index.
|
|
|
|
match registrar.voting_mint_config_index(mint) {
|
2021-12-09 07:39:06 -08:00
|
|
|
Ok(existing_idx) => require!(existing_idx == idx, VotingMintConfiguredWithDifferentIndex),
|
|
|
|
Err(_) => require!(
|
2022-01-13 06:28:40 -08:00
|
|
|
!registrar.voting_mints[idx].in_use(),
|
2021-12-09 07:39:06 -08:00
|
|
|
VotingMintConfigIndexAlreadyInUse
|
|
|
|
),
|
|
|
|
};
|
|
|
|
|
2022-01-13 06:28:40 -08:00
|
|
|
registrar.voting_mints[idx] = VotingMintConfig {
|
2021-12-09 07:39:06 -08:00
|
|
|
mint,
|
2021-12-09 02:58:15 -08:00
|
|
|
digit_shift,
|
2022-01-25 05:49:23 -08:00
|
|
|
unlocked_scaled_factor,
|
2021-12-09 02:58:15 -08:00
|
|
|
lockup_scaled_factor,
|
|
|
|
lockup_saturation_secs,
|
2021-12-20 02:09:51 -08:00
|
|
|
grant_authority: grant_authority.unwrap_or_default(),
|
2022-02-14 00:01:04 -08:00
|
|
|
reserved1: [0; 7],
|
|
|
|
reserved2: [0; 7],
|
2021-12-09 02:58:15 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Check for overflow in vote weight
|
|
|
|
registrar.max_vote_weight(ctx.remaining_accounts)?;
|
|
|
|
|
2021-12-02 07:28:12 -08:00
|
|
|
Ok(())
|
|
|
|
}
|