-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implements entry/redemption fees #55
Changes from 5 commits
73c069e
f05438a
181be4d
95fc24e
814857e
03a0ff8
bed1d38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use anchor_lang::prelude::*; | ||
|
||
#[event] | ||
pub struct PerformanceFeeUpdatedEvent { | ||
pub accountant_key: Pubkey, | ||
pub performance_fee: u64, | ||
} | ||
|
||
#[event] | ||
pub struct EntryFeeUpdatedEvent { | ||
pub accountant_key: Pubkey, | ||
pub entry_fee: u64, | ||
} | ||
|
||
#[event] | ||
pub struct RedemptionFeeUpdatedEvent { | ||
pub accountant_key: Pubkey, | ||
pub redemption_fee: u64, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,8 +12,9 @@ pub struct GenericAccountant { | |
pub index_buffer: [u8; 8], | ||
pub bump: [u8; 1], | ||
|
||
pub entry_fee: u64, | ||
pub redemption_fee: u64, | ||
pub performance_fee: u64, | ||
pub fee_recipient: Pubkey, | ||
} | ||
|
||
impl Accountant for GenericAccountant { | ||
|
@@ -36,6 +37,16 @@ impl Accountant for GenericAccountant { | |
Ok((total_fees, total_refunds)) | ||
} | ||
|
||
fn enter(&self, amount: u64) -> Result<u64> { | ||
let fee = self.entry_fee * amount / FEE_BPS; | ||
Ok(fee) | ||
} | ||
|
||
fn redeem(&self, amount: u64) -> Result<u64> { | ||
let fee = self.redemption_fee * amount / FEE_BPS; | ||
Ok(fee) | ||
} | ||
|
||
fn distribute(&mut self, accounts: &Distribute) -> Result<()> { | ||
let total = accounts.token_account.amount; | ||
|
||
|
@@ -53,22 +64,31 @@ impl Accountant for GenericAccountant { | |
) | ||
} | ||
|
||
fn set_fee(&mut self, fee: u64) -> Result<()> { | ||
fn set_performance_fee(&mut self, fee: u64) -> Result<()> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make sense, will add validation |
||
self.performance_fee = fee; | ||
Ok(()) | ||
} | ||
|
||
fn set_fee_recipient(&mut self, recipient: Pubkey) -> Result<()> { | ||
self.fee_recipient = recipient; | ||
fn set_redemption_fee(&mut self, fee: u64) -> Result<()> { | ||
self.redemption_fee = fee; | ||
Ok(()) | ||
} | ||
|
||
fn set_entry_fee(&mut self, fee: u64) -> Result<()> { | ||
self.entry_fee = fee; | ||
Ok(()) | ||
} | ||
|
||
fn performance_fee(&self) -> u64 { | ||
self.performance_fee | ||
} | ||
|
||
fn fee_recipient(&self) -> Pubkey { | ||
self.fee_recipient | ||
fn entry_fee(&self) -> u64 { | ||
self.entry_fee | ||
} | ||
|
||
fn redemption_fee(&self) -> u64 { | ||
self.redemption_fee | ||
} | ||
|
||
fn save_changes(&self, writer: &mut dyn std::io::Write) -> Result<()> { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,13 +13,24 @@ use crate::constants::{SHARES_SEED, UNDERLYING_SEED, WHITELISTED_SEED}; | |
|
||
use crate::events::VaultDepositEvent; | ||
use crate::state::Vault; | ||
use crate::utils::{token, vault}; | ||
use crate::utils::{accountant, token, vault}; | ||
|
||
#[derive(Accounts)] | ||
pub struct Deposit<'info> { | ||
#[account(mut)] | ||
pub vault: AccountLoader<'info, Vault>, | ||
|
||
/// CHECK: | ||
#[account(mut, address = vault.load()?.accountant)] | ||
pub accountant: UncheckedAccount<'info>, | ||
|
||
#[account( | ||
mut, | ||
associated_token::mint = shares_mint, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The accountant requires a token account based on the share_mint. In my opinion, it would be nice if the InitTokenAccount context of the accountant program used a more generic naming convention for the mint account, rather than underlying_mint (which, in the context of this repository, refers to the underlying_asset that users can invest with). At the very least, the current naming caused some confusion for me. |
||
associated_token::authority = accountant, | ||
)] | ||
pub accountant_recipient: Box<InterfaceAccount<'info, TokenAccount>>, | ||
|
||
#[account(mut)] | ||
pub user_token_account: InterfaceAccount<'info, TokenAccount>, | ||
|
||
|
@@ -67,15 +78,18 @@ pub struct Deposit<'info> { | |
} | ||
|
||
pub fn handle_deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> { | ||
let enter_fee = accountant::enter(&ctx.accounts.accountant, amount)?; | ||
let amount_to_deposit = amount - enter_fee; | ||
|
||
vault::validate_deposit( | ||
&ctx.accounts.vault, | ||
ctx.accounts.kyc_verified.to_account_info(), | ||
ctx.accounts.whitelisted.to_account_info(), | ||
false, | ||
amount | ||
amount_to_deposit | ||
)?; | ||
|
||
let shares = ctx.accounts.vault.load()?.convert_to_shares(amount); | ||
let mut shares = ctx.accounts.vault.load()?.convert_to_shares(amount_to_deposit); | ||
|
||
token::transfer( | ||
ctx.accounts.token_program.to_account_info(), | ||
|
@@ -95,6 +109,19 @@ pub fn handle_deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> { | |
&ctx.accounts.vault.load()?.seeds_shares(), | ||
)?; | ||
|
||
if enter_fee > 0 { | ||
let fee_shares = ctx.accounts.vault.load()?.convert_to_shares(enter_fee); | ||
shares += fee_shares; | ||
token::mint_to( | ||
ctx.accounts.shares_token_program.to_account_info(), | ||
ctx.accounts.shares_mint.to_account_info(), | ||
ctx.accounts.accountant_recipient.to_account_info(), | ||
ctx.accounts.shares_mint.to_account_info(), | ||
fee_shares, | ||
&ctx.accounts.vault.load()?.seeds_shares(), | ||
)?; | ||
} | ||
|
||
let mut vault = ctx.accounts.vault.load_mut()?; | ||
vault.handle_deposit(amount, shares); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be useful to also include timestamp to
PerformanceFeeUpdatedEvent, EntryFeeUpdatedEvent, RedemptionFeeUpdatedEvent
so that we can keep track of the fee changing history easily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't we have a timestamp in the transaction data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true, No need to strictly use Clock sysvar timestamp.