Skip to content

Commit

Permalink
Support transfer fees and other init token extensions (#142)
Browse files Browse the repository at this point in the history
* support transfer fees

* cargo change

* mint 22
  • Loading branch information
brittcyr authored Oct 8, 2024
1 parent de56325 commit 977eb1d
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 38 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion client/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ mod test {
},
};
use solana_sdk::{account::Account, account_info::AccountInfo};
use spl_token::state::Mint;
use spl_token_2022::state::Mint;
use std::{cell::RefCell, collections::HashMap, rc::Rc, str::FromStr};

#[test]
Expand Down
53 changes: 34 additions & 19 deletions programs/manifest/src/program/processor/create_market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ use solana_program::{
use spl_token_2022::{
extension::{
mint_close_authority::MintCloseAuthority, permanent_delegate::PermanentDelegate,
transfer_fee::TransferFeeConfig, BaseStateWithExtensions, StateWithExtensions,
BaseStateWithExtensions, ExtensionType, PodStateWithExtensions, StateWithExtensions,
},
state::Mint,
pod::PodMint,
state::{Account, Mint},
};

pub(crate) fn process_create_market(
Expand Down Expand Up @@ -72,13 +73,6 @@ pub(crate) fn process_create_market(
);
}
}

// Transfer fees make the amounts on withdraw and deposit not match what is expected.
require!(
pool_mint.get_extension::<TransferFeeConfig>().is_err(),
ManifestError::InvalidMint,
"Transfer fee mints are not allowed",
)?;
}
}

Expand All @@ -98,23 +92,33 @@ pub(crate) fn process_create_market(
};

let (_vault_key, bump) = get_vault_address(market.key, mint.key);
let space: usize = spl_token::state::Account::LEN;
let seeds: Vec<Vec<u8>> = vec![
b"vault".to_vec(),
market.key.as_ref().to_vec(),
mint.key.as_ref().to_vec(),
vec![bump],
];
create_account(
payer.as_ref(),
token_account,
system_program.as_ref(),
&token_program_for_mint,
&rent,
space as u64,
seeds,
)?;

if is_mint_22 {
let mint_data: Ref<'_, &mut [u8]> = mint.data.borrow();
let mint_with_extension: PodStateWithExtensions<'_, PodMint> =
PodStateWithExtensions::<PodMint>::unpack(&mint_data).unwrap();
let mint_extensions: Vec<ExtensionType> =
mint_with_extension.get_extension_types()?;
let required_extensions: Vec<ExtensionType> =
ExtensionType::get_required_init_account_extensions(&mint_extensions);
let space: usize =
ExtensionType::try_calculate_account_len::<Account>(&required_extensions)?;
create_account(
payer.as_ref(),
token_account,
system_program.as_ref(),
&token_program_for_mint,
&rent,
space as u64,
seeds,
)?;

invoke(
&spl_token_2022::instruction::initialize_account3(
&token_program_for_mint,
Expand All @@ -130,6 +134,17 @@ pub(crate) fn process_create_market(
],
)?;
} else {
let space: usize = spl_token::state::Account::LEN;
create_account(
payer.as_ref(),
token_account,
system_program.as_ref(),
&token_program_for_mint,
&rent,
space as u64,
seeds,
)?;

invoke(
&spl_token::instruction::initialize_account3(
&token_program_for_mint,
Expand Down
14 changes: 9 additions & 5 deletions programs/manifest/src/program/processor/deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub(crate) fn process_deposit(
) -> ProgramResult {
let deposit_context: DepositContext = DepositContext::load(accounts)?;
let DepositParams { amount_atoms } = DepositParams::try_from_slice(data)?;
// Due to transfer fees, this might not be what you expect.
let mut deposited_amount_atoms: u64 = amount_atoms;

let DepositContext {
market,
Expand All @@ -48,6 +50,7 @@ pub(crate) fn process_deposit(
&trader_token.try_borrow_data()?[0..32] == dynamic_account.get_base_mint().as_ref();

if *vault.owner == spl_token_2022::id() {
let before_vault_balance_atoms: u64 = vault.get_balance_atoms();
invoke(
&spl_token_2022::instruction::transfer_checked(
token_program.key,
Expand Down Expand Up @@ -76,9 +79,10 @@ pub(crate) fn process_deposit(
],
)?;

// TODO: Check the actual amount received and use that as the
// amount_atoms, rather than what the user said because of transfer
// fees.
let after_vault_balance_atoms: u64 = vault.get_balance_atoms();
deposited_amount_atoms = after_vault_balance_atoms
.checked_sub(before_vault_balance_atoms)
.unwrap();
} else {
invoke(
&spl_token::instruction::transfer(
Expand All @@ -98,7 +102,7 @@ pub(crate) fn process_deposit(
)?;
}

dynamic_account.deposit(payer.key, amount_atoms, is_base)?;
dynamic_account.deposit(payer.key, deposited_amount_atoms, is_base)?;

emit_stack(DepositLog {
market: *market.key,
Expand All @@ -108,7 +112,7 @@ pub(crate) fn process_deposit(
} else {
*dynamic_account.get_quote_mint()
},
amount_atoms,
amount_atoms: deposited_amount_atoms,
})?;

Ok(())
Expand Down
12 changes: 8 additions & 4 deletions programs/manifest/src/program/processor/global_deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub(crate) fn process_global_deposit(
) -> ProgramResult {
let global_deposit_context: GlobalDepositContext = GlobalDepositContext::load(accounts)?;
let GlobalDepositParams { amount_atoms } = GlobalDepositParams::try_from_slice(data)?;
// Due to transfer fees, this might not be what you expect.
let mut deposited_amount_atoms: u64 = amount_atoms;

let GlobalDepositContext {
payer,
Expand All @@ -47,6 +49,7 @@ pub(crate) fn process_global_deposit(

// Do the token transfer
if *global_vault.owner == spl_token_2022::id() {
let before_vault_balance_atoms: u64 = global_vault.get_balance_atoms();
invoke(
&spl_token_2022::instruction::transfer_checked(
token_program.key,
Expand All @@ -66,9 +69,10 @@ pub(crate) fn process_global_deposit(
payer.as_ref().clone(),
],
)?;
// TODO: Check the actual amount received and use that as the
// amount_atoms, rather than what the user said because of transfer
// fees.
let after_vault_balance_atoms: u64 = global_vault.get_balance_atoms();
deposited_amount_atoms = after_vault_balance_atoms
.checked_sub(before_vault_balance_atoms)
.unwrap();
} else {
invoke(
&spl_token::instruction::transfer(
Expand All @@ -91,7 +95,7 @@ pub(crate) fn process_global_deposit(
emit_stack(GlobalDepositLog {
global: *global.key,
trader: *payer.key,
global_atoms: GlobalAtoms::new(amount_atoms),
global_atoms: GlobalAtoms::new(deposited_amount_atoms),
})?;

Ok(())
Expand Down
18 changes: 13 additions & 5 deletions programs/manifest/src/validation/token_checkers.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::require;
use solana_program::{
account_info::AccountInfo, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey,
use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey};
use spl_token_2022::{
check_spl_token_program_account, extension::StateWithExtensions, state::Mint,
};
use spl_token::state::Mint;
use spl_token_2022::check_spl_token_program_account;
use std::ops::Deref;

#[derive(Clone)]
Expand All @@ -15,7 +14,8 @@ pub struct MintAccountInfo<'a, 'info> {
impl<'a, 'info> MintAccountInfo<'a, 'info> {
pub fn new(info: &'a AccountInfo<'info>) -> Result<MintAccountInfo<'a, 'info>, ProgramError> {
check_spl_token_program_account(info.owner)?;
let mint: Mint = Mint::unpack(&info.try_borrow_data()?)?;

let mint: Mint = StateWithExtensions::<Mint>::unpack(&info.data.borrow())?.base;

Ok(Self { mint, info })
}
Expand Down Expand Up @@ -59,6 +59,14 @@ impl<'a, 'info> TokenAccountInfo<'a, 'info> {
)
}

pub fn get_balance_atoms(&self) -> u64 {
u64::from_le_bytes(
self.info.try_borrow_data().unwrap()[64..72]
.try_into()
.unwrap(),
)
}

pub fn new_with_owner(
info: &'a AccountInfo<'info>,
mint: &Pubkey,
Expand Down
Loading

0 comments on commit 977eb1d

Please sign in to comment.