diff --git a/idl/drip.ts b/idl/drip.ts index ccab5c9..ac6bbe6 100644 --- a/idl/drip.ts +++ b/idl/drip.ts @@ -839,6 +839,37 @@ export type Drip = { } ], "args": [] + }, + { + "name": "adminClosePositionAccount", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "vaultProtoConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "vault", + "isMut": false, + "isSigner": false + }, + { + "name": "position", + "isMut": true, + "isSigner": false + }, + { + "name": "solDestination", + "isMut": true, + "isSigner": false + } + ], + "args": [] } ], "accounts": [ @@ -1286,6 +1317,11 @@ export type Drip = { "code": 6028, "name": "InvalidSolDestination", "msg": "Invalid sol_destination" + }, + { + "code": 6029, + "name": "PositionIsNotClosed", + "msg": "Position is not closed" } ] }; @@ -2131,6 +2167,37 @@ export const IDL: Drip = { } ], "args": [] + }, + { + "name": "adminClosePositionAccount", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "vaultProtoConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "vault", + "isMut": false, + "isSigner": false + }, + { + "name": "position", + "isMut": true, + "isSigner": false + }, + { + "name": "solDestination", + "isMut": true, + "isSigner": false + } + ], + "args": [] } ], "accounts": [ @@ -2578,6 +2645,11 @@ export const IDL: Drip = { "code": 6028, "name": "InvalidSolDestination", "msg": "Invalid sol_destination" + }, + { + "code": 6029, + "name": "PositionIsNotClosed", + "msg": "Position is not closed" } ] }; \ No newline at end of file diff --git a/idl/idl.json b/idl/idl.json index 606339d..5b53047 100644 --- a/idl/idl.json +++ b/idl/idl.json @@ -839,6 +839,37 @@ } ], "args": [] + }, + { + "name": "adminClosePositionAccount", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "vaultProtoConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "vault", + "isMut": false, + "isSigner": false + }, + { + "name": "position", + "isMut": true, + "isSigner": false + }, + { + "name": "solDestination", + "isMut": true, + "isSigner": false + } + ], + "args": [] } ], "accounts": [ @@ -1286,6 +1317,11 @@ "code": 6028, "name": "InvalidSolDestination", "msg": "Invalid sol_destination" + }, + { + "code": 6029, + "name": "PositionIsNotClosed", + "msg": "Position is not closed" } ] } \ No newline at end of file diff --git a/programs/drip/src/actions/admin.rs b/programs/drip/src/actions/admin.rs index 90a3cf5..5c3acce 100644 --- a/programs/drip/src/actions/admin.rs +++ b/programs/drip/src/actions/admin.rs @@ -1,5 +1,7 @@ use crate::errors::DripError; -use crate::instruction_accounts::{InitializeVaultAccountsBumps, WithdrawAAccounts}; +use crate::instruction_accounts::{ + ClosePositionAccountAccounts, InitializeVaultAccountsBumps, WithdrawAAccounts, +}; use crate::interactions::executor::CpiExecutor; use crate::interactions::transfer_token::TransferToken; use crate::state::{ @@ -29,6 +31,9 @@ pub enum Admin<'a, 'info> { WithdrawA { accounts: &'a mut WithdrawAAccounts<'info>, }, + ClosePositionAccount { + accounts: &'a mut ClosePositionAccountAccounts<'info>, + }, } impl<'a, 'info> Validatable for Admin<'a, 'info> { @@ -122,6 +127,24 @@ impl<'a, 'info> Validatable for Admin<'a, 'info> { DripError::VaultTokenAAccountIsEmpty ); } + Admin::ClosePositionAccount { accounts } => { + validate!( + accounts.admin.key() == accounts.vault_proto_config.admin, + DripError::SignerIsNotAdmin + ); + + validate!( + accounts.vault_proto_config.key() == accounts.vault.proto_config, + DripError::InvalidVaultProtoConfigReference + ); + + validate!( + accounts.vault.key() == accounts.position.vault.key(), + DripError::InvalidVaultReference + ); + + validate!(accounts.position.is_closed, DripError::PositionIsNotClosed); + } } Ok(()) @@ -168,6 +191,11 @@ impl<'a, 'info> Executable for Admin<'a, 'info> { let signer: &Vault = &accounts.vault; cpi_executor.execute_all(vec![&Some(&transfer_a_to_admin)], signer)?; } + Admin::ClosePositionAccount { accounts } => { + accounts + .position + .close(accounts.sol_destination.to_account_info())?; + } } Ok(()) diff --git a/programs/drip/src/errors/mod.rs b/programs/drip/src/errors/mod.rs index 832cb68..bcc71e8 100644 --- a/programs/drip/src/errors/mod.rs +++ b/programs/drip/src/errors/mod.rs @@ -61,4 +61,6 @@ pub enum DripError { VaultTokenAAccountIsEmpty, #[msg("Invalid sol_destination")] InvalidSolDestination, + #[msg("Position is not closed")] + PositionIsNotClosed, } diff --git a/programs/drip/src/instruction_accounts/admin.rs b/programs/drip/src/instruction_accounts/admin.rs index 176eacd..59b08a6 100644 --- a/programs/drip/src/instruction_accounts/admin.rs +++ b/programs/drip/src/instruction_accounts/admin.rs @@ -1,4 +1,4 @@ -use crate::state::{Vault, VaultProtoConfig}; +use crate::state::{Position, Vault, VaultProtoConfig}; use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; use anchor_spl::token::{Mint, Token, TokenAccount}; @@ -104,3 +104,19 @@ pub struct WithdrawAAccounts<'info> { pub token_program: Program<'info, Token>, } + +#[derive(Accounts)] +pub struct ClosePositionAccountAccounts<'info> { + pub admin: Signer<'info>, + + pub vault_proto_config: Account<'info, VaultProtoConfig>, + + pub vault: Account<'info, Vault>, + + #[account(mut)] + pub position: Account<'info, Position>, + + #[account(mut)] + /// CHECK: We don't care what this account is + pub sol_destination: AccountInfo<'info>, +} diff --git a/programs/drip/src/lib.rs b/programs/drip/src/lib.rs index ffe703d..6e0018b 100644 --- a/programs/drip/src/lib.rs +++ b/programs/drip/src/lib.rs @@ -113,6 +113,12 @@ pub mod drip { accounts: ctx.accounts, }) } + + pub fn admin_close_position_account(ctx: Context) -> Result<()> { + handle_action(Admin::ClosePositionAccount { + accounts: ctx.accounts, + }) + } } fn handle_action(action: impl Validatable + Executable) -> Result<()> { diff --git a/programs/drip/src/state/position.rs b/programs/drip/src/state/position.rs index ee9fe30..e4663e2 100644 --- a/programs/drip/src/state/position.rs +++ b/programs/drip/src/state/position.rs @@ -21,8 +21,9 @@ pub struct Position { pub number_of_swaps: u64, // 8 // deposit_amount_token_a / number_of_swaps pub periodic_drip_amount: u64, // 8 - pub is_closed: bool, // 1 - pub bump: u8, // 1 + // DEPRECATED FIELD: Position accounts are closed now instead of being marked closed + pub is_closed: bool, // 1 + pub bump: u8, // 1 } impl Position { @@ -63,10 +64,6 @@ impl Position { pub fn increase_withdrawn_amount(&mut self, amount: u64) { self.withdrawn_token_b_amount = self.withdrawn_token_b_amount.checked_add(amount).unwrap(); } - - pub fn close(&mut self) { - self.is_closed = true; - } } test_account_size!(Position); diff --git a/yarn.lock b/yarn.lock index e8134fa..c9abad2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2971,9 +2971,9 @@ __metadata: linkType: hard "ip@npm:^2.0.0": - version: 2.0.0 - resolution: "ip@npm:2.0.0" - checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 + version: 2.0.1 + resolution: "ip@npm:2.0.1" + checksum: d765c9fd212b8a99023a4cde6a558a054c298d640fec1020567494d257afd78ca77e37126b1a3ef0e053646ced79a816bf50621d38d5e768cdde0431fa3b0d35 languageName: node linkType: hard