Add internal_transfer_unlocked
Rename internal_transfer -> internal_transfer_locked The new instruction can move only unlocked funds and is useful to avoid needing to withdraw funds if they should be re-locked in a different deposit entry. Withdrawing can be impossible when a voter is engaged in proposals.
This commit is contained in:
parent
e7ffe744e9
commit
7b7ce7d8ce
|
@ -132,7 +132,7 @@ If you want access to the tokens again, you need to start the unlocking process
|
||||||
by either
|
by either
|
||||||
- changing the whole deposit entry to `Cliff` with `ResetLockup`, or
|
- changing the whole deposit entry to `Cliff` with `ResetLockup`, or
|
||||||
- creating a new `Cliff` deposit entry and transfering some locked tokens from
|
- creating a new `Cliff` deposit entry and transfering some locked tokens from
|
||||||
your `Constant` deposit entry over with `InternalTransfer`.
|
your `Constant` deposit entry over with `InternalTransferLocked`.
|
||||||
|
|
||||||
In both cases you'll need to wait for the cliff to be reached before being able
|
In both cases you'll need to wait for the cliff to be reached before being able
|
||||||
to access the tokens again.
|
to access the tokens again.
|
||||||
|
@ -176,11 +176,16 @@ to access the tokens again.
|
||||||
Re-lock tokens where the lockup has expired, or increase the duration of the lockup or
|
Re-lock tokens where the lockup has expired, or increase the duration of the lockup or
|
||||||
change the lockup kind.
|
change the lockup kind.
|
||||||
|
|
||||||
- [`InternalTransfer`](programs/voter-stake-registry/src/instructions/internal_transfer.rs)
|
- [`InternalTransferLocked`](programs/voter-stake-registry/src/instructions/internal_transfer_locked.rs)
|
||||||
|
|
||||||
Transfer locked tokens from one deposit entry to another. Useful for splitting off a
|
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.
|
chunk of a "constant" lockup deposit entry that you want to start the unlock process on.
|
||||||
|
|
||||||
|
- [`InternalTransferUnocked`](programs/voter-stake-registry/src/instructions/internal_transfer_unlocked.rs)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
- [`UpdateVoterWeightRecord`](programs/voter-stake-registry/src/instructions/update_voter_weight_record.rs)
|
- [`UpdateVoterWeightRecord`](programs/voter-stake-registry/src/instructions/update_voter_weight_record.rs)
|
||||||
|
|
||||||
Write the current voter weight to the account that spl-governance can read to
|
Write the current voter weight to the account that spl-governance can read to
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::state::*;
|
||||||
use anchor_lang::prelude::*;
|
use anchor_lang::prelude::*;
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
pub struct InternalTransfer<'info> {
|
pub struct InternalTransferLocked<'info> {
|
||||||
pub registrar: AccountLoader<'info, Registrar>,
|
pub registrar: AccountLoader<'info, Registrar>,
|
||||||
|
|
||||||
// checking the PDA address it just an extra precaution,
|
// checking the PDA address it just an extra precaution,
|
||||||
|
@ -31,8 +31,8 @@ pub struct InternalTransfer<'info> {
|
||||||
/// - transfering a small part of a big "constant" lockup deposit entry into a "cliff"
|
/// - transfering a small part of a big "constant" lockup deposit entry into a "cliff"
|
||||||
/// locked deposit entry to start the unlocking process (reset_lockup could only
|
/// locked deposit entry to start the unlocking process (reset_lockup could only
|
||||||
/// change the whole deposit entry to "cliff")
|
/// change the whole deposit entry to "cliff")
|
||||||
pub fn internal_transfer(
|
pub fn internal_transfer_locked(
|
||||||
ctx: Context<InternalTransfer>,
|
ctx: Context<InternalTransferLocked>,
|
||||||
source_deposit_entry_index: u8,
|
source_deposit_entry_index: u8,
|
||||||
target_deposit_entry_index: u8,
|
target_deposit_entry_index: u8,
|
||||||
amount: u64,
|
amount: u64,
|
|
@ -0,0 +1,59 @@
|
||||||
|
use crate::error::*;
|
||||||
|
use crate::state::*;
|
||||||
|
use anchor_lang::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Accounts)]
|
||||||
|
pub struct InternalTransferUnlocked<'info> {
|
||||||
|
pub registrar: AccountLoader<'info, Registrar>,
|
||||||
|
|
||||||
|
// checking the PDA address it just an extra precaution,
|
||||||
|
// the other constraints must be exhaustive
|
||||||
|
#[account(
|
||||||
|
mut,
|
||||||
|
seeds = [registrar.key().as_ref(), b"voter".as_ref(), voter_authority.key().as_ref()],
|
||||||
|
bump = voter.load()?.voter_bump,
|
||||||
|
has_one = voter_authority,
|
||||||
|
has_one = registrar)]
|
||||||
|
pub voter: AccountLoader<'info, Voter>,
|
||||||
|
pub voter_authority: Signer<'info>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transfers unlocked tokens from the source deposit entry to the target deposit entry.
|
||||||
|
///
|
||||||
|
/// Note that this never transfers locked tokens, only tokens that are unlocked.
|
||||||
|
///
|
||||||
|
/// The primary usecase is moving some deposited funds from one deposit entry to
|
||||||
|
/// another because the user wants to lock them, without having to withdraw and re-deposit
|
||||||
|
/// them.
|
||||||
|
pub fn internal_transfer_unlocked(
|
||||||
|
ctx: Context<InternalTransferUnlocked>,
|
||||||
|
source_deposit_entry_index: u8,
|
||||||
|
target_deposit_entry_index: u8,
|
||||||
|
amount: u64,
|
||||||
|
) -> Result<()> {
|
||||||
|
let registrar = &ctx.accounts.registrar.load()?;
|
||||||
|
let voter = &mut ctx.accounts.voter.load_mut()?;
|
||||||
|
let curr_ts = registrar.clock_unix_timestamp();
|
||||||
|
|
||||||
|
let source = voter.active_deposit_mut(source_deposit_entry_index)?;
|
||||||
|
let source_mint_idx = source.voting_mint_config_idx;
|
||||||
|
|
||||||
|
// Reduce source amounts
|
||||||
|
require!(
|
||||||
|
amount <= source.amount_withdrawable(curr_ts),
|
||||||
|
InsufficientVestedTokens
|
||||||
|
);
|
||||||
|
source.amount_deposited_native = source.amount_deposited_native.checked_sub(amount).unwrap();
|
||||||
|
|
||||||
|
// Check target compatibility
|
||||||
|
let target = voter.active_deposit_mut(target_deposit_entry_index)?;
|
||||||
|
require!(
|
||||||
|
target.voting_mint_config_idx == source_mint_idx,
|
||||||
|
InvalidMint
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add target amounts
|
||||||
|
target.amount_deposited_native = target.amount_deposited_native.checked_add(amount).unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -7,7 +7,8 @@ pub use create_registrar::*;
|
||||||
pub use create_voter::*;
|
pub use create_voter::*;
|
||||||
pub use deposit::*;
|
pub use deposit::*;
|
||||||
pub use grant::*;
|
pub use grant::*;
|
||||||
pub use internal_transfer::*;
|
pub use internal_transfer_locked::*;
|
||||||
|
pub use internal_transfer_unlocked::*;
|
||||||
pub use log_voter_info::*;
|
pub use log_voter_info::*;
|
||||||
pub use reset_lockup::*;
|
pub use reset_lockup::*;
|
||||||
pub use set_time_offset::*;
|
pub use set_time_offset::*;
|
||||||
|
@ -24,7 +25,8 @@ mod create_registrar;
|
||||||
mod create_voter;
|
mod create_voter;
|
||||||
mod deposit;
|
mod deposit;
|
||||||
mod grant;
|
mod grant;
|
||||||
mod internal_transfer;
|
mod internal_transfer_locked;
|
||||||
|
mod internal_transfer_unlocked;
|
||||||
mod log_voter_info;
|
mod log_voter_info;
|
||||||
mod reset_lockup;
|
mod reset_lockup;
|
||||||
mod set_time_offset;
|
mod set_time_offset;
|
||||||
|
|
|
@ -162,13 +162,27 @@ pub mod voter_stake_registry {
|
||||||
instructions::reset_lockup(ctx, deposit_entry_index, kind, periods)
|
instructions::reset_lockup(ctx, deposit_entry_index, kind, periods)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn internal_transfer(
|
pub fn internal_transfer_locked(
|
||||||
ctx: Context<InternalTransfer>,
|
ctx: Context<InternalTransferLocked>,
|
||||||
source_deposit_entry_index: u8,
|
source_deposit_entry_index: u8,
|
||||||
target_deposit_entry_index: u8,
|
target_deposit_entry_index: u8,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
instructions::internal_transfer(
|
instructions::internal_transfer_locked(
|
||||||
|
ctx,
|
||||||
|
source_deposit_entry_index,
|
||||||
|
target_deposit_entry_index,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn internal_transfer_unlocked(
|
||||||
|
ctx: Context<InternalTransferUnlocked>,
|
||||||
|
source_deposit_entry_index: u8,
|
||||||
|
target_deposit_entry_index: u8,
|
||||||
|
amount: u64,
|
||||||
|
) -> Result<()> {
|
||||||
|
instructions::internal_transfer_unlocked(
|
||||||
ctx,
|
ctx,
|
||||||
source_deposit_entry_index,
|
source_deposit_entry_index,
|
||||||
target_deposit_entry_index,
|
target_deposit_entry_index,
|
||||||
|
|
Loading…
Reference in New Issue