Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Security

## dynamic-amm-quote [0.0.5] - PR[#204](https://github.com/MeteoraAg/dynamic-amm-sdk/pull/204/)

### Changed

- Support fee curve quote

## dynamic-amm [0.6.2] - PR[#204](https://github.com/MeteoraAg/dynamic-amm-sdk/pull/204/)

- Add fee curve related state in `Pool` account

## @meteora-ag/dynamic-amm-sdk [1.3.2] - PR[#204](https://github.com/MeteoraAg/dynamic-amm-sdk/pull/204/)

### Changed

- improve stake pool price
- `createCustomizablePermissionlessConstantProductPool` function `customizableParams` now require `feeCurve`. See [test](./ts-client/src/amm/tests/initializeCustomizablePermissionlessConstantProductPool.test.ts) example.
- `createCustomizablePermissionlessConstantProductPool` function `customizableParams` no longer need to pass in `padding`
- `calculateTradingFee` and `calculateProtocolTradingFee` function receive `PoolFees` instead of `PoolState`

## commons [0.0.5] - PR[#195](https://github.com/MeteoraAG/dynamic-amm-sdk/pull/195)

### Added
Expand Down
9 changes: 4 additions & 5 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ members = ["programs/*", "rust-client", "dynamic-amm-quote", "common"]
resolver = "2"

[workspace.package]
version = "0.0.5"
version = "0.0.6"
authors = ["Andrew"]
edition = "2021"
8 changes: 4 additions & 4 deletions dynamic-amm-quote/src/depeg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use anyhow::{Context, Result};
use prog_dynamic_amm::constants::depeg::BASE_CACHE_EXPIRES;
use prog_dynamic_amm::state::CurveType;
use prog_dynamic_amm::state::DepegType;
use prog_dynamic_amm::state::Pool;
use std::collections::HashMap;

/// Marinade module consists of functions to support marinade depeg pool operation
Expand All @@ -29,11 +28,12 @@ fn get_stake_pool_virtual_price(

/// Update depeg base virtual price
pub fn update_base_virtual_price(
pool: &mut Pool,
curve_type: &mut CurveType,
clock: &Clock,
stake_data: HashMap<Pubkey, Vec<u8>>,
spl_stake_pool: Pubkey,
) -> Result<()> {
match &mut pool.curve_type {
match curve_type {
CurveType::ConstantProduct => Ok(()),
CurveType::Stable { depeg, .. } => {
if !depeg.depeg_type.is_none() {
Expand All @@ -44,7 +44,7 @@ pub fn update_base_virtual_price(

if clock.unix_timestamp as u64 > cache_expire_time {
let virtual_price =
get_stake_pool_virtual_price(depeg.depeg_type, pool.stake, stake_data)
get_stake_pool_virtual_price(depeg.depeg_type, spl_stake_pool, stake_data)
.context("Fail to get stake pool virtual price")?;

depeg.base_cache_updated = clock.unix_timestamp as u64;
Expand Down
30 changes: 27 additions & 3 deletions dynamic-amm-quote/src/depeg/spl_stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,33 @@ use std::convert::TryInto;
pub fn get_virtual_price(bytes: &[u8]) -> Option<u64> {
let stake: StakePool = borsh0_10::try_from_slice_unchecked(bytes).ok()?;

let virtual_price = (stake.total_lamports as u128)
.checked_mul(depeg::PRECISION as u128)?
.checked_div(stake.pool_token_supply as u128)?;
let total_lamports: u128 = stake.total_lamports.into();
let pool_token_supply: u128 = stake.pool_token_supply.into();

// may be higher if we apply deposit fee
let deposit_price = total_lamports
.checked_mul(depeg::PRECISION.into())?
.checked_div(pool_token_supply)?;

let withdraw_fee_denominator: u128 = stake.sol_withdrawal_fee.denominator.into();
let withdraw_fee_numerator: u128 = stake.sol_withdrawal_fee.numerator.into();

// sanity check
if withdraw_fee_denominator <= withdraw_fee_numerator.checked_mul(10)? {
return deposit_price.try_into().ok();
}

let withdraw_price = total_lamports
.checked_mul(withdraw_fee_denominator.checked_sub(withdraw_fee_numerator)?)?
.checked_mul(depeg::PRECISION.into())?
.checked_div(withdraw_fee_denominator)?
.checked_div(pool_token_supply)?;

// deposit price has weight more than 3 times with withdraw price
let virtual_price = deposit_price
.checked_mul(3)?
.checked_add(withdraw_price)?
.checked_div(4)?;

virtual_price.try_into().ok()
}
64 changes: 57 additions & 7 deletions dynamic-amm-quote/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ use crate::math::*;
use anchor_lang::prelude::*;
use anchor_spl::token::{Mint, TokenAccount};
use anyhow::{anyhow, ensure, Context};
use prog_dynamic_amm::constants::FEE_CURVE_POINT_NUMBER;
use prog_dynamic_amm::error::PoolError;
use prog_dynamic_amm::state::{ActivationType, Pool};
use prog_dynamic_amm::state::{ActivationType, FeeCurveType, Pool, PoolFees};
use prog_dynamic_vault::state::Vault;
use spl_token_swap::curve::calculator::TradeDirection;
use std::collections::HashMap;
Expand Down Expand Up @@ -61,7 +62,7 @@ pub fn compute_quote(
quote_data: QuoteData,
) -> anyhow::Result<QuoteResult> {
let QuoteData {
mut pool,
pool,
vault_a,
vault_b,
pool_vault_a_lp_token,
Expand All @@ -88,7 +89,8 @@ pub fn compute_quote(
"Swap is disabled"
);

update_base_virtual_price(&mut pool, &clock, stake_data)?;
let mut curve = pool.curve_type;
update_base_virtual_price(&mut curve, &clock, stake_data, pool.stake)?;

let current_time: u64 = clock.unix_timestamp.try_into()?;

Expand Down Expand Up @@ -151,13 +153,13 @@ pub fn compute_quote(
),
};

let trade_fee = pool
.fees
let latest_pool_fees = get_latest_pool_fees(&pool, current_point)?;

let trade_fee = latest_pool_fees
.trading_fee(in_amount.into())
.context("Fail to calculate trading fee")?;

let protocol_fee = pool
.fees
let protocol_fee = latest_pool_fees
.protocol_trading_fee(trade_fee)
.context("Fail to calculate protocol trading fee")?;

Expand Down Expand Up @@ -259,3 +261,51 @@ pub fn compute_pool_tokens(
.ok_or(PoolError::MathOverflow)?;
Ok((token_a_amount, token_b_amount))
}

pub fn get_latest_pool_fees(state: &Pool, current_point: u64) -> anyhow::Result<PoolFees> {
if state.fee_curve.fee_curve_type == FeeCurveType::None || state.is_update_fee_completed {
return Ok(state.fees);
}

let points = state.fee_curve.points;

let get_latest_trade_bps = move || -> u16 {
for i in 0..FEE_CURVE_POINT_NUMBER {
// current_point is between i-1 and i
if points[i].activated_point >= current_point {
if i == 0 {
return points[i].fee_bps;
}
if state.fee_curve.fee_curve_type == FeeCurveType::Flat {
return points[i - 1].fee_bps;
}

let m: u64 = points[i - 1].fee_bps.into();
let n: u64 = points[i].fee_bps.into();
let a = points[i - 1].activated_point;
let b = points[i].activated_point;

let denominator = b - a;
if denominator == 0 {
return m as u16;
} else {
let numerator = n * (current_point - a) + m * (b - current_point);
return (numerator / denominator) as u16;
}
}
}
points[FEE_CURVE_POINT_NUMBER - 1].fee_bps
};

let latest_trade_fee_bps = get_latest_trade_bps();
let trade_fee_numerator = u64::from(latest_trade_fee_bps)
.checked_mul(10)
.context("Overflow")?;

Ok(PoolFees {
trade_fee_numerator,
trade_fee_denominator: state.fees.trade_fee_denominator,
protocol_trade_fee_numerator: state.fees.protocol_trade_fee_numerator,
protocol_trade_fee_denominator: state.fees.protocol_trade_fee_denominator,
})
}
Binary file modified dynamic-amm-quote/tests/fixtures/dynamic_amm.so
Binary file not shown.
2 changes: 1 addition & 1 deletion programs/dynamic-amm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dynamic-amm"
version = "0.6.1"
version = "0.6.2"
description = "Created with Anchor"
edition = "2021"

Expand Down
4 changes: 4 additions & 0 deletions programs/dynamic-amm/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use anchor_lang::solana_program::pubkey;
/// Minimum seconds between last AMP changes
pub const MIN_CHANGE_AMP_DURATION: u64 = 600; // 10 minutes

pub const FEE_CURVE_POINT_NUMBER: usize = 7;

pub const FEE_CURVE_DURATION_NUMBER: usize = 6;

pub mod seeds {
pub const CONFIG_PREFIX: &[u8] = b"config";
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
constants::{activation::*, fee::*, QUOTE_MINTS},
constants::{activation::*, fee::*, FEE_CURVE_DURATION_NUMBER, QUOTE_MINTS},
error::PoolError,
get_first_key, get_lp_mint_decimal, get_second_key,
state::Pool,
state::{FeeCurveType, Pool},
};
use anchor_lang::prelude::*;
use anchor_spl::{
Expand Down Expand Up @@ -166,6 +166,22 @@ pub struct InitializeCustomizablePermissionlessConstantProductPool<'info> {
pub system_program: Program<'info, System>,
}

#[derive(Copy, Clone, Debug, AnchorSerialize, AnchorDeserialize, InitSpace, Default, PartialEq)]
pub struct FeeBpsFromDuration {
// Fee bps
pub fee_bps: u16, //u16::MAX = 65_535 > 10_000
// Activated duration (from current point)
pub activated_duration: u32,
}

#[derive(Copy, Clone, Debug, AnchorSerialize, AnchorDeserialize, Default, InitSpace, PartialEq)]
pub struct FeeCurveInfoFromDuration {
/// Fee curve type, could be flat or linear
pub fee_curve_type: FeeCurveType,
/// Fee curve point
pub points: [FeeBpsFromDuration; FEE_CURVE_DURATION_NUMBER],
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy)]
pub struct CustomizableParams {
/// Trading fee.
Expand All @@ -176,6 +192,8 @@ pub struct CustomizableParams {
pub has_alpha_vault: bool,
/// Activation type
pub activation_type: u8,
/// Fee curve info
pub fee_curve: FeeCurveInfoFromDuration,
/// Padding
pub padding: [u8; 90],
pub padding: [u8; 53],
}
42 changes: 40 additions & 2 deletions programs/dynamic-amm/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Pool account state
use crate::constants;
use crate::constants::{self, FEE_CURVE_POINT_NUMBER};
use anchor_lang::prelude::*;
use std::fmt::Debug;

Expand Down Expand Up @@ -28,11 +28,28 @@ pub struct Padding {
/// Padding 0
pub padding_0: [u8; 6], // 6
/// Padding 1
pub padding_1: [u64; 21], // 168
pub padding_1: [u64; 12], // 96
/// Padding 2
pub padding_2: [u64; 21], // 168
}

/// Fee curve type
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Debug, PartialEq, InitSpace)]
pub enum FeeCurveType {
/// No dynamic fee
None,
/// Flat
Flat,
/// Linear (we dont allow this fee curve type now)
Linear,
}

impl Default for FeeCurveType {
fn default() -> Self {
FeeCurveType::None
}
}

/// Host fee
pub struct HostFee<'c, 'info> {
/// Host fee
Expand Down Expand Up @@ -96,11 +113,32 @@ pub struct Pool {
/// Bootstrapping config
pub bootstrapping: Bootstrapping,
pub partner_info: PartnerInfo,
/// fee curve
pub fee_curve: FeeCurveInfo,
/// Flag to indicate that fee update onchain is completed
pub is_update_fee_completed: bool,
/// Padding for future pool field
pub padding: Padding,
/// The type of the swap curve supported by the pool.
// Leaving curve_type as last field give us the flexibility to add specific curve information / new curve type
pub curve_type: CurveType, //9
pub _padding1: [u8; 19],
}

#[derive(Copy, Clone, Debug, AnchorSerialize, AnchorDeserialize, Default, InitSpace)]
pub struct FeeCurveInfo {
/// Fee curve type, could be flat or linear
pub fee_curve_type: FeeCurveType,
/// Fee curve point
pub points: [FeeBpsFromActivatedPoint; FEE_CURVE_POINT_NUMBER],
}

#[derive(Copy, Clone, Debug, AnchorSerialize, AnchorDeserialize, InitSpace, Default)]
pub struct FeeBpsFromActivatedPoint {
// fee_bps
pub fee_bps: u16, //u16::MAX = 65_535 > 10000
// Activated point
pub activated_point: u64,
}

#[derive(Copy, Clone, Debug, AnchorSerialize, AnchorDeserialize, InitSpace, Default)]
Expand Down
1 change: 0 additions & 1 deletion rust-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ solana-rpc-client = { version = "1.16.0" }
solana-sdk = { version = "1.16.0" }
spl-associated-token-account = "2.2.0"
anyhow = "1.0.57"
spl-token = "3.5.0"
bincode = "1.3.3"
serde = "1.0.137"
serde_json = "1.0.102"
Expand Down
Loading
Loading