Withdraw: Never block withdraws of tokens without voting power
Previously being engaged in a proposal would prohibit these withdraws.
This commit is contained in:
parent
997767a06e
commit
929c38f512
|
@ -87,12 +87,18 @@ pub fn withdraw(ctx: Context<Withdraw>, deposit_entry_index: u8, amount: u64) ->
|
|||
let registrar = &ctx.accounts.registrar.load()?;
|
||||
let voter = &mut ctx.accounts.voter.load_mut()?;
|
||||
|
||||
// Get the exchange rate for the token being withdrawn.
|
||||
let mint_idx = registrar.voting_mint_config_index(ctx.accounts.destination.mint)?;
|
||||
|
||||
// Governance may forbid withdraws, for example when engaged in a vote.
|
||||
let token_owner_record = voter.load_token_owner_record(
|
||||
&ctx.accounts.token_owner_record.to_account_info(),
|
||||
registrar,
|
||||
)?;
|
||||
token_owner_record.assert_can_withdraw_governing_tokens()?;
|
||||
// Not applicable for tokens that don't contribute to voting power.
|
||||
if registrar.voting_mints[mint_idx].grants_vote_weight() {
|
||||
let token_owner_record = voter.load_token_owner_record(
|
||||
&ctx.accounts.token_owner_record.to_account_info(),
|
||||
registrar,
|
||||
)?;
|
||||
token_owner_record.assert_can_withdraw_governing_tokens()?;
|
||||
}
|
||||
|
||||
// Get the deposit being withdrawn from.
|
||||
let curr_ts = registrar.clock_unix_timestamp();
|
||||
|
@ -101,9 +107,6 @@ pub fn withdraw(ctx: Context<Withdraw>, deposit_entry_index: u8, amount: u64) ->
|
|||
deposit_entry.amount_unlocked(curr_ts) >= amount,
|
||||
InsufficientUnlockedTokens
|
||||
);
|
||||
|
||||
// Get the exchange rate for the token being withdrawn.
|
||||
let mint_idx = registrar.voting_mint_config_index(ctx.accounts.destination.mint)?;
|
||||
require!(
|
||||
mint_idx == deposit_entry.voting_mint_config_idx as usize,
|
||||
ErrorCode::InvalidMint
|
||||
|
|
|
@ -85,6 +85,15 @@ impl VotingMintConfig {
|
|||
pub fn in_use(&self) -> bool {
|
||||
self.mint != Pubkey::default()
|
||||
}
|
||||
|
||||
/// Do tokens of this mint contribute to voting weight?
|
||||
///
|
||||
/// DAOs may configure mints without any vote weight contributions if they
|
||||
/// want to use the grant / vesting / clawback functionality for non-voting
|
||||
/// tokens like USDC.
|
||||
pub fn grants_vote_weight(&self) -> bool {
|
||||
self.unlocked_scaled_factor > 0 || self.lockup_scaled_factor > 0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Zeroable for VotingMintConfig {}
|
||||
|
|
|
@ -103,6 +103,7 @@ impl AddinCookie {
|
|||
lockup_scaled_factor: f64,
|
||||
lockup_saturation_secs: u64,
|
||||
grant_authority: Option<Pubkey>,
|
||||
other_mints: Option<&[Pubkey]>,
|
||||
) -> VotingMintConfigCookie {
|
||||
let deposit_mint = mint.pubkey.unwrap();
|
||||
|
||||
|
@ -129,6 +130,11 @@ impl AddinCookie {
|
|||
deposit_mint,
|
||||
false,
|
||||
));
|
||||
for mint in other_mints.unwrap_or(&[]) {
|
||||
accounts.push(anchor_lang::prelude::AccountMeta::new_readonly(
|
||||
*mint, false,
|
||||
));
|
||||
}
|
||||
|
||||
let instructions = vec![Instruction {
|
||||
program_id: self.program_id,
|
||||
|
|
|
@ -46,6 +46,7 @@ async fn test_all_deposits() -> Result<(), TransportError> {
|
|||
0.0,
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
0.0,
|
||||
1,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let mngo_voting_mint = context
|
||||
|
@ -62,6 +63,7 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
0.0,
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ async fn test_clawback() -> Result<(), TransportError> {
|
|||
0.0,
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ async fn test_deposit_cliff() -> Result<(), TransportError> {
|
|||
1.0,
|
||||
2 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ async fn test_deposit_constant() -> Result<(), TransportError> {
|
|||
1.0,
|
||||
2 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ async fn test_deposit_daily_vesting() -> Result<(), TransportError> {
|
|||
0.5,
|
||||
60 * 60 * 60, // 60h / 2.5d
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ async fn test_deposit_monthly_vesting() -> Result<(), TransportError> {
|
|||
0.0,
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ async fn test_deposit_no_locking() -> Result<(), TransportError> {
|
|||
10.0, // no locking, so has no effect
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ async fn test_grants() -> Result<(), TransportError> {
|
|||
0.0,
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
Some(grant_authority.pubkey()),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ async fn test_internal_transfer() -> Result<(), TransportError> {
|
|||
0.0,
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ async fn test_log_voter_info() -> Result<(), TransportError> {
|
|||
1.0,
|
||||
365 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ async fn test_reset_lockup() -> Result<(), TransportError> {
|
|||
0.0,
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ async fn test_voting() -> Result<(), TransportError> {
|
|||
let voter_authority = &context.users[1].key;
|
||||
let voter2_authority = &context.users[2].key;
|
||||
let voter_mngo = context.users[1].token_accounts[0];
|
||||
let voter_usdc = context.users[1].token_accounts[1];
|
||||
let token_owner_record = realm
|
||||
.create_token_owner_record(voter_authority.pubkey(), &payer)
|
||||
.await;
|
||||
|
@ -50,6 +51,22 @@ async fn test_voting() -> Result<(), TransportError> {
|
|||
0.0,
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let usdc_voting_mint = addin
|
||||
.configure_voting_mint(
|
||||
®istrar,
|
||||
&realm_authority,
|
||||
payer,
|
||||
1,
|
||||
&context.mints[1],
|
||||
0,
|
||||
0.0,
|
||||
0.0,
|
||||
5 * 365 * 24 * 60 * 60,
|
||||
None,
|
||||
Some(&[context.mints[0].pubkey.unwrap()]),
|
||||
)
|
||||
.await;
|
||||
|
||||
|
@ -177,6 +194,33 @@ async fn test_voting() -> Result<(), TransportError> {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
addin
|
||||
.create_deposit_entry(
|
||||
®istrar,
|
||||
&voter2,
|
||||
voter2_authority,
|
||||
&usdc_voting_mint,
|
||||
1,
|
||||
LockupKind::None,
|
||||
None,
|
||||
0,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
addin
|
||||
.deposit(
|
||||
®istrar,
|
||||
&voter2,
|
||||
&usdc_voting_mint,
|
||||
voter_authority,
|
||||
voter_usdc,
|
||||
1,
|
||||
1000,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
realm
|
||||
.cast_vote(
|
||||
mint_governance.address,
|
||||
|
@ -211,6 +255,20 @@ async fn test_voting() -> Result<(), TransportError> {
|
|||
.await
|
||||
.expect_err("could not withdraw");
|
||||
|
||||
// but can withdraw USDC
|
||||
addin
|
||||
.withdraw(
|
||||
®istrar,
|
||||
&voter2,
|
||||
&usdc_voting_mint,
|
||||
&voter2_authority,
|
||||
voter_usdc,
|
||||
1,
|
||||
1,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
realm
|
||||
.relinquish_vote(
|
||||
mint_governance.address,
|
||||
|
|
Loading…
Reference in New Issue