Parcel #glxm5dth1gvowby

Created by Anonymous
Public

Created April 28, 2025 Expires in 19 days

Loading editor...

use anchor_gen::generate_cpi_crate;

generate_cpi_crate!("./idl.json");
declare_id!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P");

const BUY_SIGNATURE: [u8; 8] = [102, 6, 61, 18, 1, 218, 235, 234];
const SELL_SIGNATURE: [u8; 8] = [51, 230, 133, 164, 1, 127, 131, 173];

impl BondingCurve {
    pub fn fee(&self, config: &Global, amount: u128) -> u128 {
        amount * (config.fee_basis_points as u128) / 10000
    }

    pub fn buy_quote(&self, config: &Global, amount: u64, is_exact_in: bool) -> u64 {
        let mut amount = amount as u128;
        let virtual_sol_reserves = self.virtual_sol_reserves as u128;
        let virtual_token_reserves = self.virtual_token_reserves as u128;
        let real_token_reserves = self.real_token_reserves as u128;

        let (max_amount_in, amount_out) = if is_exact_in {
            let k = virtual_sol_reserves * virtual_token_reserves;
            let new_sol_reserves = virtual_sol_reserves + amount;
            let new_token_reserves = k.checked_div(new_sol_reserves).unwrap_or(0) + 1;
            let mut amount_out = virtual_token_reserves.saturating_sub(new_token_reserves);
            amount_out = std::cmp::min(amount_out, real_token_reserves);
            (amount, amount_out)
        } else {
            amount = std::cmp::min(amount, real_token_reserves);
            let max_amount_in = (amount * virtual_sol_reserves)
                .checked_div(virtual_token_reserves - amount)
                .unwrap_or(0)
                + 1;
            (max_amount_in, amount)
        };
        if is_exact_in {
            amount_out as u64
        } else {
            let fee = self.fee(config, max_amount_in);
            (max_amount_in + fee) as u64
        }
    }

    pub fn sell_quote(&self, amount_in: u64) -> u64 {
        let amount_in = amount_in as u128;
        let virtual_sol_reserves = self.virtual_sol_reserves as u128;
        let virtual_token_reserves = self.virtual_token_reserves as u128;

        let numerator = amount_in.checked_mul(virtual_sol_reserves).unwrap_or(0);
        let denominator = virtual_token_reserves.checked_add(amount_in).unwrap_or(0);
        let amount_out = numerator.checked_div(denominator).unwrap_or(0);

        amount_out as u64
    }

    pub fn get_amount_out(&self, config: &Global, amount_in: u64, is_buy: bool) -> u64 {
        match is_buy {
            true => {
                let denominator = 10000 + config.fee_basis_points as u128;
                let amount_in_less_fee = amount_in as u128 * 10000 / denominator;

                self.buy_quote(config, amount_in_less_fee as u64, true)
            }
            false => {
                let amount_out = self.sell_quote(amount_in);

                if amount_out > self.real_sol_reserves {
                    return 0;
                }

                let fee = self.fee(config, amount_out as u128) as u64;

                amount_out.saturating_sub(fee)
            }
        }
    }

    pub fn encode_swap(&self, config: &Global, is_buy: bool, amount_in: u64) -> Vec<u8> {
        let mut data = Vec::default();

        if is_buy {
            data.extend(BUY_SIGNATURE);

            let amount_out = self.get_amount_out(config, amount_in, is_buy);
            instruction::Buy { _amount: amount_out, _max_sol_cost: amount_in }
                .serialize(&mut data)
                .unwrap();
        } else {
            data.extend(SELL_SIGNATURE);
            instruction::Sell { _amount: amount_in, _min_sol_output: 0 }
                .serialize(&mut data)
                .unwrap();
        }

        data
    }
}