Add instruction for closing deposits

This commit is contained in:
Christian Kamm 2021-11-30 11:49:59 +01:00
parent d529dab2d6
commit 2c608ebe46
6 changed files with 96 additions and 1 deletions

View File

@ -262,10 +262,17 @@ impl<'info> Withdraw<'info> {
}
}
#[derive(Accounts)]
pub struct CloseDeposit<'info> {
#[account(mut, has_one = authority)]
pub voter: AccountLoader<'info, Voter>,
pub authority: Signer<'info>,
}
#[derive(Accounts)]
pub struct UpdateSchedule<'info> {
pub registrar: AccountLoader<'info, Registrar>,
#[account(mut, has_one = authority)]
#[account(mut, has_one = authority, has_one = registrar)]
pub voter: AccountLoader<'info, Voter>,
pub authority: Signer<'info>,
}

View File

@ -217,6 +217,7 @@ pub mod governance_registry {
require!(voter.deposits.len() > id as usize, InvalidDepositId);
let d_entry = &mut voter.deposits[id as usize];
require!(d_entry.is_used, InvalidDepositId);
// Deposit tokens into the registrar.
token::transfer(ctx.accounts.transfer_ctx(), amount)?;
@ -359,6 +360,22 @@ pub mod governance_registry {
Ok(())
}
/// Close an empty deposit, allowing it to be reused in the future
pub fn close_deposit(ctx: Context<CloseDeposit>, deposit_id: u8) -> Result<()> {
let voter = &mut ctx.accounts.voter.load_mut()?;
require!(voter.deposits.len() > deposit_id as usize, InvalidDepositId);
let d = &mut voter.deposits[deposit_id as usize];
require!(d.is_used, InvalidDepositId);
require!(d.amount_deposited_native == 0, VotingTokenNonZero);
// We do not need to check d.amount_initially_locked_native or d.lockup
// here - the fact that the deposit contains no tokens is sufficient.
d.is_used = false;
Ok(())
}
/// Resets a lockup to start at the current slot timestamp and to last for
/// `periods`, which must be >= the number of periods left on the lockup.
/// This will re-lock any non-withdrawn vested funds.

View File

@ -410,6 +410,38 @@ impl AddinCookie {
.await)
}
pub async fn close_deposit(
&self,
voter: &VoterCookie,
authority: &Keypair,
deposit_id: u8,
) -> Result<(), TransportError> {
let data = anchor_lang::InstructionData::data(
&governance_registry::instruction::CloseDeposit { deposit_id },
);
let accounts = anchor_lang::ToAccountMetas::to_account_metas(
&governance_registry::accounts::CloseDeposit {
voter: voter.address,
authority: authority.pubkey(),
},
None,
);
let instructions = vec![Instruction {
program_id: self.program_id,
accounts,
data,
}];
// clone the secrets
let signer = Keypair::from_base58_string(&authority.to_base58_string());
self.solana
.process_transaction(&instructions, Some(&[&signer]))
.await
}
pub async fn set_time_offset(
&self,
registrar: &RegistrarCookie,

View File

@ -226,5 +226,7 @@ async fn test_deposit_daily_vesting() -> Result<(), TransportError> {
assert_eq!(after_withdraw.vault, 0);
assert_eq!(after_withdraw.deposit, 0);
addin.close_deposit(&voter, &voter_authority, 0).await.unwrap();
Ok(())
}

View File

@ -227,6 +227,9 @@ async fn test_deposit_monthly_vesting() -> Result<(), TransportError> {
assert_eq!(after_deposit.vault, 1000);
assert_eq!(after_deposit.deposit, 1000);
// cannot close yet, has funds
addin.close_deposit(&voter, &voter_authority, 0).await.expect_err("deposit not empty");
withdraw(1000).await.unwrap();
let after_withdraw = get_balances(0).await;
@ -235,5 +238,7 @@ async fn test_deposit_monthly_vesting() -> Result<(), TransportError> {
assert_eq!(after_withdraw.vault, 0);
assert_eq!(after_withdraw.deposit, 0);
addin.close_deposit(&voter, &voter_authority, 0).await.unwrap();
Ok(())
}

View File

@ -194,6 +194,17 @@ async fn test_deposit_no_locking() -> Result<(), TransportError> {
assert_eq!(after_withdraw2.vault, 7000);
assert_eq!(after_withdraw2.deposit, 0);
// Close the empty deposit (closing deposits 1 and 2 fails)
addin.close_deposit(&voter, &voter_authority, 2).await.expect_err("deposit not in use");
addin.close_deposit(&voter, &voter_authority, 1).await.expect_err("deposit not empty");
addin.close_deposit(&voter, &voter_authority, 0).await.unwrap();
let after_close = get_balances(0).await;
assert_eq!(initial.token, after_close.token + after_close.vault);
assert_eq!(after_close.voter_weight, after_close.vault);
assert_eq!(after_close.vault, 7000);
assert_eq!(after_close.deposit, 0);
// check that the voter2 account is still at 0
let voter2_balances = balances(
&context,
@ -236,5 +247,26 @@ async fn test_deposit_no_locking() -> Result<(), TransportError> {
assert_eq!(voter2_balances.voter_weight, 1000);
assert_eq!(voter2_balances.vault, 8000);
// when voter1 deposits again, they can reuse deposit index 0
addin
.create_deposit(
&registrar,
&voter,
&mngo_rate,
&voter_authority,
reference_account,
governance_registry::account::LockupKind::Monthly,
3000,
1,
)
.await
.unwrap();
let after_reuse = get_balances(0).await;
assert_eq!(initial.token, after_reuse.token + 7000 + 3000);
assert_eq!(after_reuse.voter_weight, 7000 + 3000);
assert_eq!(after_reuse.vault, 8000 + 3000);
assert_eq!(after_reuse.deposit, 3000);
Ok(())
}