Skip to content
Merged
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
6 changes: 3 additions & 3 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 auction-server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "auction-server"
version = "0.33.0"
version = "0.34.0"
edition = "2021"
license-file = "license.txt"

Expand Down
2 changes: 1 addition & 1 deletion auction-server/api-types/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "express-relay-api-types"
version = "0.12.0"
version = "0.12.1"
edition = "2021"
description = "Pyth Express Relay api types"
repository = "https://github.com/pyth-network/per"
Expand Down
2 changes: 2 additions & 0 deletions auction-server/api-types/src/opportunity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ pub enum OpportunityParamsV1ProgramSvm {
#[serde_as(as = "DisplayFromStr")]
router_account: Pubkey,

#[deprecated = "This field is deprecated and will be removed in a future release."]
// TODO this should be deleted
/// The referral fee in basis points.
#[schema(example = 10)]
Expand All @@ -234,6 +235,7 @@ pub enum OpportunityParamsV1ProgramSvm {
#[schema(example = 1000)]
referral_fee_ppm: u64,

#[deprecated = "This field is deprecated and will be removed in a future release."]
// TODO this should be deleted
/// The platform fee in basis points.
#[schema(example = 10)]
Expand Down
6 changes: 5 additions & 1 deletion auction-server/config.sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,18 @@ chains:
- So11111111111111111111111111111111111111112
- EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
allow_permissionless_quote_requests: true
minimum_fee_list:
minimum_referral_fee_list:
profiles:
- profile_id: 0b059fa2-189f-4498-a646-e7ee1ed79c3c
minimum_fees:
- mint: Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB
fee_ppm: 100
- mint: So11111111111111111111111111111111111111112
fee_ppm: 200
minimum_platform_fee_list:
minimum_fees:
- mint: So11111111111111111111111111111111111111112
fee_ppm: 100

lazer:
price_feeds:
Expand Down
2 changes: 1 addition & 1 deletion auction-server/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ impl std::fmt::Display for SwapInstructionError {
),
SwapInstructionError::ReferralFee { expected, found } => write!(
f,
"Invalid referral fee bps {} in swap instruction data. Value does not match the referral fee bps in swap opportunity {}",
"Invalid referral fee ppm {} in swap instruction data. Value does not match the referral fee ppm in swap opportunity {}",
found, expected
),
SwapInstructionError::AssociatedRouterTokenAccount { expected, found } => write!(
Expand Down
19 changes: 15 additions & 4 deletions auction-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,12 @@ pub struct ConfigSvm {
/// Whitelisted token mints
#[serde(default)]
pub token_whitelist: TokenWhitelistConfig,
/// Minimum fee list
/// Minimum referral fee list
#[serde(default)]
pub minimum_fee_list: MinimumFeeListConfig,
pub minimum_referral_fee_list: MinimumReferralFeeListConfig,
/// Minimum platform fee list
#[serde(default)]
pub minimum_platform_fee_list: MinimumPlatformFeeListConfig,
/// Whether to allow permissionless quote requests.
#[serde(default)]
pub allow_permissionless_quote_requests: bool,
Expand Down Expand Up @@ -207,14 +210,22 @@ pub struct TokenWhitelistConfig {
pub whitelist_mints: Vec<Pubkey>,
}

/// Optional minimum fee list to determine validity of quote request
/// Minimum referral fee list to determine validity of quote request
#[serde_as]
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct MinimumFeeListConfig {
pub struct MinimumReferralFeeListConfig {
#[serde(default)]
pub profiles: Vec<MinimumFeeProfile>,
}

/// Minimum platform fee list to determine platform fees to apply to quote requests
#[serde_as]
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct MinimumPlatformFeeListConfig {
#[serde(default)]
pub minimum_fees: Vec<MinimumFee>,
}

#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct MinimumFeeProfile {
pub profile_id: Option<Uuid>,
Expand Down
27 changes: 20 additions & 7 deletions auction-server/src/opportunity/service/get_quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ use {
solana_sdk::pubkey::Pubkey,
spl_associated_token_account::get_associated_token_address_with_program_id,
spl_token::native_mint,
std::time::Duration,
std::{
cmp::max,
time::Duration,
},
time::OffsetDateTime,
tokio::time::sleep,
};
Expand Down Expand Up @@ -214,6 +217,14 @@ impl Service {
})
.await?;

let platform_fee_pair_ppm = config
.get_platform_fee_ppm(&mint_user, &mint_searcher)
.unwrap_or(0);
let platform_fee_ppm = max(
platform_fee_pair_ppm,
metadata.swap_platform_fee_bps * FEE_BPS_TO_PPM,
);

let fee_token = get_fee_token(mint_user, mint_searcher, &config.ordered_fee_tokens);
let (searcher_amount, user_amount) = match (quote_create.tokens.clone(), fee_token.clone())
{
Expand All @@ -224,15 +235,14 @@ impl Service {
// This is not exactly accurate and may overestimate the amount needed
// because of floor / ceil rounding errors.
let referral_fee_ppm = referral_fee_info.referral_fee_ppm;
let swap_platform_fee_ppm = metadata.swap_platform_fee_bps * FEE_BPS_TO_PPM;
if referral_fee_ppm + swap_platform_fee_ppm >= FEE_SPLIT_PRECISION_PPM {
if referral_fee_ppm + platform_fee_ppm >= FEE_SPLIT_PRECISION_PPM {
return Err(RestError::BadParameters(format!(
"Referral fee ppm + platform fee ppm must be less than {}",
FEE_SPLIT_PRECISION_PPM
)));
}
let denominator: u64 =
FEE_SPLIT_PRECISION_PPM - referral_fee_ppm - swap_platform_fee_ppm;
FEE_SPLIT_PRECISION_PPM - referral_fee_ppm - platform_fee_ppm;
let numerator = searcher_token.amount * FEE_SPLIT_PRECISION_PPM;
let amount_including_fees = numerator.div_ceil(denominator);
(amount_including_fees, 0u64)
Expand Down Expand Up @@ -349,7 +359,7 @@ impl Service {
// token_account_initialization_configs.router_fee_receiver_ta =
// TokenAccountInitializationConfig::Unneeded;
}
if metadata.swap_platform_fee_bps == 0 {
if platform_fee_ppm == 0 {
// If the platform fee is 0, we can skip the initialization of the express relay and relayer token accounts
token_account_initialization_configs.express_relay_fee_receiver_ata =
TokenAccountInitializationConfig::Unneeded;
Expand All @@ -374,8 +384,11 @@ impl Service {
fee_token,
referral_fee_bps,
referral_fee_ppm: referral_fee_info.referral_fee_ppm,
platform_fee_bps: metadata.swap_platform_fee_bps,
platform_fee_ppm: metadata.swap_platform_fee_bps * FEE_BPS_TO_PPM,
// TODO: we should deprecate and then get rid of the bps fields.
// For now we keep them for backwards compatibility, and generally the fees are in bp units.
// But if searchers are using the bps fields to calculate the ppm fields, this will lead to SwapInstructionError::PlatformFee if the fees are ever non-unit bps.
platform_fee_bps: platform_fee_ppm / FEE_BPS_TO_PPM,
platform_fee_ppm,
token_program_user,
user_mint_user_balance,
token_account_initialization_configs,
Expand Down
64 changes: 50 additions & 14 deletions auction-server/src/opportunity/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use {
self as auction_service,
},
config::{
MinimumFeeListConfig,
MinimumPlatformFeeListConfig,
MinimumReferralFeeListConfig,
TokenWhitelistConfig,
},
kernel::{
Expand Down Expand Up @@ -115,7 +116,8 @@ pub struct ConfigSvm {
pub ordered_fee_tokens: Vec<Pubkey>,
pub auction_service_container: AuctionServiceContainer,
pub token_whitelist: TokenWhitelist,
pub minimum_fee_list: MinimumFeeList,
pub minimum_referral_fee_list: MinimumReferralFeeList,
pub minimum_platform_fee_list: Vec<MinimumFee>,
pub allow_permissionless_quote_requests: bool,
pub auction_time: Duration,
}
Expand Down Expand Up @@ -150,9 +152,14 @@ impl ConfigSvm {
.token_whitelist
.clone()
.into(),
minimum_fee_list: chain_store
minimum_referral_fee_list: chain_store
.config
.minimum_fee_list
.minimum_referral_fee_list
.clone()
.into(),
minimum_platform_fee_list: chain_store
.config
.minimum_platform_fee_list
.clone()
.into(),
allow_permissionless_quote_requests: chain_store
Expand Down Expand Up @@ -219,10 +226,10 @@ impl ConfigSvm {
}

let minimum_fee_searcher = self
.minimum_fee_list
.minimum_referral_fee_list
.get_minimum_fee(&mint_searcher, profile_id);
let minimum_fee_user = self
.minimum_fee_list
.minimum_referral_fee_list
.get_minimum_fee(&mint_user, profile_id);

if referral_fee_ppm
Expand Down Expand Up @@ -255,11 +262,26 @@ impl ConfigSvm {

Ok(())
}

pub fn get_platform_fee_ppm(&self, mint_user: &Pubkey, mint_searcher: &Pubkey) -> Option<u64> {
let fee_user = self
.minimum_platform_fee_list
.iter()
.find(|fee| &fee.mint == mint_user)
.map(|fee| fee.fee_ppm);
let fee_searcher = self
.minimum_platform_fee_list
.iter()
.find(|fee| &fee.mint == mint_searcher)
.map(|fee| fee.fee_ppm);

fee_user.into_iter().chain(fee_searcher).max()
}
}

/// Optional minimum fee list for token mints
/// Optional minimum referral fee list for token mints
#[derive(Clone, Default)]
pub struct MinimumFeeList {
pub struct MinimumReferralFeeList {
pub profiles: Vec<MinimumFeeProfile>,
}

Expand All @@ -275,7 +297,7 @@ pub struct MinimumFee {
pub fee_ppm: u64,
}

impl MinimumFeeList {
impl MinimumReferralFeeList {
pub fn get_minimum_fee(&self, mint: &Pubkey, profile_id: Option<Uuid>) -> Option<u64> {
let mut minimum_fee = self
.profiles
Expand All @@ -289,8 +311,8 @@ impl MinimumFeeList {
.map(|fee| fee.fee_ppm)
});

// The minimum fee list can include an entry with no profile_id, which can be used as a fallback if no match is found for the specific profile_id.
// This allows for a default minimum fee to be applied if no specific profile is found.
// The minimum referral fee list can include an entry with no profile_id, which can be used as a fallback if no match is found for the specific profile_id.
// This allows for a default minimum referral fee to be applied if no specific profile is found.
if minimum_fee.is_none() {
minimum_fee = self
.profiles
Expand All @@ -309,8 +331,8 @@ impl MinimumFeeList {
}
}

impl From<MinimumFeeListConfig> for MinimumFeeList {
fn from(value: MinimumFeeListConfig) -> Self {
impl From<MinimumReferralFeeListConfig> for MinimumReferralFeeList {
fn from(value: MinimumReferralFeeListConfig) -> Self {
Self {
profiles: value
.profiles
Expand All @@ -331,6 +353,19 @@ impl From<MinimumFeeListConfig> for MinimumFeeList {
}
}

impl From<MinimumPlatformFeeListConfig> for Vec<MinimumFee> {
fn from(value: MinimumPlatformFeeListConfig) -> Self {
value
.minimum_fees
.into_iter()
.map(|fee| MinimumFee {
mint: fee.mint,
fee_ppm: fee.fee_ppm,
})
.collect()
}
}

/// Optional whitelist for token mints
#[derive(Clone, Default)]
pub struct TokenWhitelist {
Expand Down Expand Up @@ -433,7 +468,8 @@ pub mod tests {
ordered_fee_tokens: vec![],
auction_service_container: AuctionServiceContainer::new(),
token_whitelist: Default::default(),
minimum_fee_list: Default::default(),
minimum_referral_fee_list: Default::default(),
minimum_platform_fee_list: Default::default(),
allow_permissionless_quote_requests: true,
auction_time: config::ConfigSvm::default_auction_time(),
};
Expand Down
8 changes: 7 additions & 1 deletion integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,20 @@ def main():
- {mint_sell}
- So11111111111111111111111111111111111111112
allow_permissionless_quote_requests: true
minimum_fee_list:
minimum_referral_fee_list:
profiles:
- profile_id: 4b4f8bcf-415a-4509-be21-bd803cdc8937
minimum_fees:
- mint: {mint_buy}
fee_ppm: 200
- mint: {mint_sell}
fee_ppm: 0
minimum_platform_fee_list:
minimum_fees:
- mint: {mint_buy}
fee_ppm: 100
- mint: {mint_sell}
fee_ppm: 1099
lazer:
price_feeds:
- id: 1
Expand Down
4 changes: 2 additions & 2 deletions sdk/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[package]
name = "express-relay-client"
version = "0.13.0"
version = "0.14.0"
edition = "2021"
description = "Pyth Express Relay client"
repository = "https://github.com/pyth-network/per"
license = "Apache-2.0"

[dependencies]
express-relay-api-types = { version = "0.12.0", path = "../../auction-server/api-types" }
express-relay-api-types = { version = "0.12.1", path = "../../auction-server/api-types" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to update the "express-relay-client" version

reqwest = { version = "0.12.9", features = ["json"] }
url = { workspace = true}
serde = { workspace = true }
Expand Down
4 changes: 2 additions & 2 deletions sdk/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ impl Client {
tokens,
fee_token,
router_account,
referral_fee_bps,
referral_fee_ppm,
token_account_initialization_configs,
memo,
..
Expand Down Expand Up @@ -755,7 +755,7 @@ impl Client {
fee_token_program,
router_account,
fee_receiver_relayer: params.fee_receiver_relayer,
referral_fee_bps,
referral_fee_ppm,
chain_id: opportunity_params.chain_id.clone(),
configs: token_account_initialization_configs.clone(),
},
Expand Down
Loading
Loading