use {
crate::types::{
LiquidityPoolAllowlist, LiquidityPoolFeatureFlags, LiquidityPoolInfo,
LiquidityPoolLpTokenInfo, LiquidityPoolMarketCapBasedFees, LiquidityPoolReserve,
LiquidityPoolSlotOffsetBasedFees, LiquidityPoolTokenInfo,
},
carbon_core::{
account::AccountMetadata,
postgres::{
metadata::AccountRowMetadata,
primitives::{Pubkey, U64, U8},
},
},
};
#[derive(sqlx::FromRow, Debug, Clone)]
pub struct LiquidityPoolStateRow {
#[sqlx(flatten)]
pub account_metadata: AccountRowMetadata,
pub info: sqlx::types::Json<LiquidityPoolInfo>,
pub market_cap_based_fees: sqlx::types::Json<LiquidityPoolMarketCapBasedFees>,
pub reserve: sqlx::types::Json<LiquidityPoolReserve>,
pub lp_token: sqlx::types::Json<LiquidityPoolLpTokenInfo>,
pub protocol_trading_fees: U64,
pub creator_trading_fees: U64,
pub creator_trading_fees_claimed_by_creator: U64,
pub creator_trading_fees_claimed_by_others: U64,
pub liquidity_provider_trading_fees: U64,
pub creator_trading_fee_protocol_fees: U64,
pub reflection_trading_fees: U64,
pub created_at_slot: U64,
pub trading_volume_usd: f64,
pub creator_trading_fee_trading_volume_threshold: f64,
pub creator_trading_fee_trading_volume_threshold_reached_unix_timestamp: U64,
pub token_a_vault: Pubkey,
pub token_b_vault: Pubkey,
pub protocol_config: Pubkey,
pub key: Pubkey,
pub token_a: sqlx::types::Json<LiquidityPoolTokenInfo>,
pub token_b: sqlx::types::Json<LiquidityPoolTokenInfo>,
pub allowlist: sqlx::types::Json<LiquidityPoolAllowlist>,
pub feature_flags: sqlx::types::Json<LiquidityPoolFeatureFlags>,
pub taxable_side: U8,
pub taxable_side_type: U8,
pub creator_trading_fee_distribution: U8,
pub creator_trading_fee_claim_status: U8,
pub fee_configuration_mode: U8,
pub is_migrated: U8,
pub pad: Vec<u8>,
pub slot_offset_based_fees: sqlx::types::Json<LiquidityPoolSlotOffsetBasedFees>,
pub creator_trading_fee_receiver: Pubkey,
}
impl LiquidityPoolStateRow {
pub fn from_parts(
source: crate::accounts::liquidity_pool_state::LiquidityPoolState,
metadata: AccountMetadata,
) -> Self {
Self {
account_metadata: metadata.into(),
info: sqlx::types::Json(source.info),
market_cap_based_fees: sqlx::types::Json(source.market_cap_based_fees),
reserve: sqlx::types::Json(source.reserve),
lp_token: sqlx::types::Json(source.lp_token),
protocol_trading_fees: source.protocol_trading_fees.into(),
creator_trading_fees: source.creator_trading_fees.into(),
creator_trading_fees_claimed_by_creator: source
.creator_trading_fees_claimed_by_creator
.into(),
creator_trading_fees_claimed_by_others: source
.creator_trading_fees_claimed_by_others
.into(),
liquidity_provider_trading_fees: source.liquidity_provider_trading_fees.into(),
creator_trading_fee_protocol_fees: source.creator_trading_fee_protocol_fees.into(),
reflection_trading_fees: source.reflection_trading_fees.into(),
created_at_slot: source.created_at_slot.into(),
trading_volume_usd: source.trading_volume_usd,
creator_trading_fee_trading_volume_threshold: source
.creator_trading_fee_trading_volume_threshold,
creator_trading_fee_trading_volume_threshold_reached_unix_timestamp: source
.creator_trading_fee_trading_volume_threshold_reached_unix_timestamp
.into(),
token_a_vault: source.token_a_vault.into(),
token_b_vault: source.token_b_vault.into(),
protocol_config: source.protocol_config.into(),
key: source.key.into(),
token_a: sqlx::types::Json(source.token_a),
token_b: sqlx::types::Json(source.token_b),
allowlist: sqlx::types::Json(source.allowlist),
feature_flags: sqlx::types::Json(source.feature_flags),
taxable_side: source.taxable_side.into(),
taxable_side_type: source.taxable_side_type.into(),
creator_trading_fee_distribution: source.creator_trading_fee_distribution.into(),
creator_trading_fee_claim_status: source.creator_trading_fee_claim_status.into(),
fee_configuration_mode: source.fee_configuration_mode.into(),
is_migrated: source.is_migrated.into(),
pad: source.pad.to_vec(),
slot_offset_based_fees: sqlx::types::Json(source.slot_offset_based_fees),
creator_trading_fee_receiver: source.creator_trading_fee_receiver.into(),
}
}
}
impl TryFrom<LiquidityPoolStateRow> for crate::accounts::liquidity_pool_state::LiquidityPoolState {
type Error = carbon_core::error::Error;
fn try_from(source: LiquidityPoolStateRow) -> Result<Self, Self::Error> {
Ok(Self {
info: source.info.0,
market_cap_based_fees: source.market_cap_based_fees.0,
reserve: source.reserve.0,
lp_token: source.lp_token.0,
protocol_trading_fees: *source.protocol_trading_fees,
creator_trading_fees: *source.creator_trading_fees,
creator_trading_fees_claimed_by_creator: *source
.creator_trading_fees_claimed_by_creator,
creator_trading_fees_claimed_by_others: *source.creator_trading_fees_claimed_by_others,
liquidity_provider_trading_fees: *source.liquidity_provider_trading_fees,
creator_trading_fee_protocol_fees: *source.creator_trading_fee_protocol_fees,
reflection_trading_fees: *source.reflection_trading_fees,
created_at_slot: *source.created_at_slot,
trading_volume_usd: source.trading_volume_usd,
creator_trading_fee_trading_volume_threshold: source
.creator_trading_fee_trading_volume_threshold,
creator_trading_fee_trading_volume_threshold_reached_unix_timestamp: *source
.creator_trading_fee_trading_volume_threshold_reached_unix_timestamp,
token_a_vault: *source.token_a_vault,
token_b_vault: *source.token_b_vault,
protocol_config: *source.protocol_config,
key: *source.key,
token_a: source.token_a.0,
token_b: source.token_b.0,
allowlist: source.allowlist.0,
feature_flags: source.feature_flags.0,
taxable_side: source.taxable_side.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
taxable_side_type: source.taxable_side_type.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
creator_trading_fee_distribution: source
.creator_trading_fee_distribution
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
creator_trading_fee_claim_status: source
.creator_trading_fee_claim_status
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
fee_configuration_mode: source.fee_configuration_mode.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
is_migrated: source.is_migrated.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
pad: source.pad.as_slice().try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert padding from postgres primitive: expected 13 bytes"
.to_string(),
)
})?,
slot_offset_based_fees: source.slot_offset_based_fees.0,
creator_trading_fee_receiver: *source.creator_trading_fee_receiver,
})
}
}
impl carbon_core::postgres::operations::Table
for crate::accounts::liquidity_pool_state::LiquidityPoolState
{
fn table() -> &'static str {
"liquidity_pool_state_account"
}
fn columns() -> Vec<&'static str> {
vec![
"__pubkey",
"__slot",
"info",
"market_cap_based_fees",
"reserve",
"lp_token",
"protocol_trading_fees",
"creator_trading_fees",
"creator_trading_fees_claimed_by_creator",
"creator_trading_fees_claimed_by_others",
"liquidity_provider_trading_fees",
"creator_trading_fee_protocol_fees",
"reflection_trading_fees",
"created_at_slot",
"trading_volume_usd",
"creator_trading_fee_trading_volume_threshold",
"creator_trading_fee_trading_volume_threshold_reached_unix_timestamp",
"token_a_vault",
"token_b_vault",
"protocol_config",
"key",
"token_a",
"token_b",
"allowlist",
"feature_flags",
"taxable_side",
"taxable_side_type",
"creator_trading_fee_distribution",
"creator_trading_fee_claim_status",
"fee_configuration_mode",
"is_migrated",
"pad",
"slot_offset_based_fees",
"creator_trading_fee_receiver",
]
}
}
#[async_trait::async_trait]
impl carbon_core::postgres::operations::Insert for LiquidityPoolStateRow {
async fn insert(&self, pool: &sqlx::PgPool) -> carbon_core::error::CarbonResult<()> {
sqlx::query(r#"
INSERT INTO liquidity_pool_state_account (
"info",
"market_cap_based_fees",
"reserve",
"lp_token",
"protocol_trading_fees",
"creator_trading_fees",
"creator_trading_fees_claimed_by_creator",
"creator_trading_fees_claimed_by_others",
"liquidity_provider_trading_fees",
"creator_trading_fee_protocol_fees",
"reflection_trading_fees",
"created_at_slot",
"trading_volume_usd",
"creator_trading_fee_trading_volume_threshold",
"creator_trading_fee_trading_volume_threshold_reached_unix_timestamp",
"token_a_vault",
"token_b_vault",
"protocol_config",
"key",
"token_a",
"token_b",
"allowlist",
"feature_flags",
"taxable_side",
"taxable_side_type",
"creator_trading_fee_distribution",
"creator_trading_fee_claim_status",
"fee_configuration_mode",
"is_migrated",
"pad",
"slot_offset_based_fees",
"creator_trading_fee_receiver",
__pubkey, __slot
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34
)"#)
.bind(&self.info)
.bind(&self.market_cap_based_fees)
.bind(&self.reserve)
.bind(&self.lp_token)
.bind(&self.protocol_trading_fees)
.bind(&self.creator_trading_fees)
.bind(&self.creator_trading_fees_claimed_by_creator)
.bind(&self.creator_trading_fees_claimed_by_others)
.bind(&self.liquidity_provider_trading_fees)
.bind(&self.creator_trading_fee_protocol_fees)
.bind(&self.reflection_trading_fees)
.bind(&self.created_at_slot)
.bind(self.trading_volume_usd)
.bind(self.creator_trading_fee_trading_volume_threshold)
.bind(&self.creator_trading_fee_trading_volume_threshold_reached_unix_timestamp)
.bind(self.token_a_vault)
.bind(self.token_b_vault)
.bind(self.protocol_config)
.bind(self.key)
.bind(&self.token_a)
.bind(&self.token_b)
.bind(&self.allowlist)
.bind(&self.feature_flags)
.bind(self.taxable_side)
.bind(self.taxable_side_type)
.bind(self.creator_trading_fee_distribution)
.bind(self.creator_trading_fee_claim_status)
.bind(self.fee_configuration_mode)
.bind(self.is_migrated)
.bind(&self.pad)
.bind(&self.slot_offset_based_fees)
.bind(self.creator_trading_fee_receiver)
.bind(self.account_metadata.pubkey)
.bind(&self.account_metadata.slot)
.execute(pool).await
.map_err(|e| carbon_core::error::Error::Custom(e.to_string()))?;
Ok(())
}
}
#[async_trait::async_trait]
impl carbon_core::postgres::operations::Upsert for LiquidityPoolStateRow {
async fn upsert(&self, pool: &sqlx::PgPool) -> carbon_core::error::CarbonResult<()> {
sqlx::query(r#"INSERT INTO liquidity_pool_state_account (
"info",
"market_cap_based_fees",
"reserve",
"lp_token",
"protocol_trading_fees",
"creator_trading_fees",
"creator_trading_fees_claimed_by_creator",
"creator_trading_fees_claimed_by_others",
"liquidity_provider_trading_fees",
"creator_trading_fee_protocol_fees",
"reflection_trading_fees",
"created_at_slot",
"trading_volume_usd",
"creator_trading_fee_trading_volume_threshold",
"creator_trading_fee_trading_volume_threshold_reached_unix_timestamp",
"token_a_vault",
"token_b_vault",
"protocol_config",
"key",
"token_a",
"token_b",
"allowlist",
"feature_flags",
"taxable_side",
"taxable_side_type",
"creator_trading_fee_distribution",
"creator_trading_fee_claim_status",
"fee_configuration_mode",
"is_migrated",
"pad",
"slot_offset_based_fees",
"creator_trading_fee_receiver",
__pubkey, __slot
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34
) ON CONFLICT (
__pubkey
) DO UPDATE SET
"info" = EXCLUDED."info",
"market_cap_based_fees" = EXCLUDED."market_cap_based_fees",
"reserve" = EXCLUDED."reserve",
"lp_token" = EXCLUDED."lp_token",
"protocol_trading_fees" = EXCLUDED."protocol_trading_fees",
"creator_trading_fees" = EXCLUDED."creator_trading_fees",
"creator_trading_fees_claimed_by_creator" = EXCLUDED."creator_trading_fees_claimed_by_creator",
"creator_trading_fees_claimed_by_others" = EXCLUDED."creator_trading_fees_claimed_by_others",
"liquidity_provider_trading_fees" = EXCLUDED."liquidity_provider_trading_fees",
"creator_trading_fee_protocol_fees" = EXCLUDED."creator_trading_fee_protocol_fees",
"reflection_trading_fees" = EXCLUDED."reflection_trading_fees",
"created_at_slot" = EXCLUDED."created_at_slot",
"trading_volume_usd" = EXCLUDED."trading_volume_usd",
"creator_trading_fee_trading_volume_threshold" = EXCLUDED."creator_trading_fee_trading_volume_threshold",
"creator_trading_fee_trading_volume_threshold_reached_unix_timestamp" = EXCLUDED."creator_trading_fee_trading_volume_threshold_reached_unix_timestamp",
"token_a_vault" = EXCLUDED."token_a_vault",
"token_b_vault" = EXCLUDED."token_b_vault",
"protocol_config" = EXCLUDED."protocol_config",
"key" = EXCLUDED."key",
"token_a" = EXCLUDED."token_a",
"token_b" = EXCLUDED."token_b",
"allowlist" = EXCLUDED."allowlist",
"feature_flags" = EXCLUDED."feature_flags",
"taxable_side" = EXCLUDED."taxable_side",
"taxable_side_type" = EXCLUDED."taxable_side_type",
"creator_trading_fee_distribution" = EXCLUDED."creator_trading_fee_distribution",
"creator_trading_fee_claim_status" = EXCLUDED."creator_trading_fee_claim_status",
"fee_configuration_mode" = EXCLUDED."fee_configuration_mode",
"is_migrated" = EXCLUDED."is_migrated",
"pad" = EXCLUDED."pad",
"slot_offset_based_fees" = EXCLUDED."slot_offset_based_fees",
"creator_trading_fee_receiver" = EXCLUDED."creator_trading_fee_receiver",
__slot = EXCLUDED.__slot
"#)
.bind(&self.info)
.bind(&self.market_cap_based_fees)
.bind(&self.reserve)
.bind(&self.lp_token)
.bind(&self.protocol_trading_fees)
.bind(&self.creator_trading_fees)
.bind(&self.creator_trading_fees_claimed_by_creator)
.bind(&self.creator_trading_fees_claimed_by_others)
.bind(&self.liquidity_provider_trading_fees)
.bind(&self.creator_trading_fee_protocol_fees)
.bind(&self.reflection_trading_fees)
.bind(&self.created_at_slot)
.bind(self.trading_volume_usd)
.bind(self.creator_trading_fee_trading_volume_threshold)
.bind(&self.creator_trading_fee_trading_volume_threshold_reached_unix_timestamp)
.bind(self.token_a_vault)
.bind(self.token_b_vault)
.bind(self.protocol_config)
.bind(self.key)
.bind(&self.token_a)
.bind(&self.token_b)
.bind(&self.allowlist)
.bind(&self.feature_flags)
.bind(self.taxable_side)
.bind(self.taxable_side_type)
.bind(self.creator_trading_fee_distribution)
.bind(self.creator_trading_fee_claim_status)
.bind(self.fee_configuration_mode)
.bind(self.is_migrated)
.bind(&self.pad)
.bind(&self.slot_offset_based_fees)
.bind(self.creator_trading_fee_receiver)
.bind(self.account_metadata.pubkey)
.bind(&self.account_metadata.slot)
.execute(pool).await
.map_err(|e| carbon_core::error::Error::Custom(e.to_string()))?;
Ok(())
}
}
#[async_trait::async_trait]
impl carbon_core::postgres::operations::Delete for LiquidityPoolStateRow {
type Key = carbon_core::postgres::primitives::Pubkey;
async fn delete(key: Self::Key, pool: &sqlx::PgPool) -> carbon_core::error::CarbonResult<()> {
sqlx::query(
r#"DELETE FROM liquidity_pool_state_account WHERE
__pubkey = $1
"#,
)
.bind(key)
.execute(pool)
.await
.map_err(|e| carbon_core::error::Error::Custom(e.to_string()))?;
Ok(())
}
}
#[async_trait::async_trait]
impl carbon_core::postgres::operations::Lookup for LiquidityPoolStateRow {
type Key = carbon_core::postgres::primitives::Pubkey;
async fn lookup(
key: Self::Key,
pool: &sqlx::PgPool,
) -> carbon_core::error::CarbonResult<Option<Self>> {
let row = sqlx::query_as(
r#"SELECT * FROM liquidity_pool_state_account WHERE
__pubkey = $1
"#,
)
.bind(key)
.fetch_optional(pool)
.await
.map_err(|e| carbon_core::error::Error::Custom(e.to_string()))?;
Ok(row)
}
}
pub struct LiquidityPoolStateMigrationOperation;
#[async_trait::async_trait]
impl sqlx_migrator::Operation<sqlx::Postgres> for LiquidityPoolStateMigrationOperation {
async fn up(
&self,
connection: &mut sqlx::PgConnection,
) -> Result<(), sqlx_migrator::error::Error> {
sqlx::query(r#"CREATE TABLE IF NOT EXISTS liquidity_pool_state_account (
-- Account data
"info" JSONB NOT NULL,
"market_cap_based_fees" JSONB NOT NULL,
"reserve" JSONB NOT NULL,
"lp_token" JSONB NOT NULL,
"protocol_trading_fees" NUMERIC(20) NOT NULL,
"creator_trading_fees" NUMERIC(20) NOT NULL,
"creator_trading_fees_claimed_by_creator" NUMERIC(20) NOT NULL,
"creator_trading_fees_claimed_by_others" NUMERIC(20) NOT NULL,
"liquidity_provider_trading_fees" NUMERIC(20) NOT NULL,
"creator_trading_fee_protocol_fees" NUMERIC(20) NOT NULL,
"reflection_trading_fees" NUMERIC(20) NOT NULL,
"created_at_slot" NUMERIC(20) NOT NULL,
"trading_volume_usd" DOUBLE PRECISION NOT NULL,
"creator_trading_fee_trading_volume_threshold" DOUBLE PRECISION NOT NULL,
"creator_trading_fee_trading_volume_threshold_reached_unix_timestamp" NUMERIC(20) NOT NULL,
"token_a_vault" BYTEA NOT NULL,
"token_b_vault" BYTEA NOT NULL,
"protocol_config" BYTEA NOT NULL,
"key" BYTEA NOT NULL,
"token_a" JSONB NOT NULL,
"token_b" JSONB NOT NULL,
"allowlist" JSONB NOT NULL,
"feature_flags" JSONB NOT NULL,
"taxable_side" INT2 NOT NULL,
"taxable_side_type" INT2 NOT NULL,
"creator_trading_fee_distribution" INT2 NOT NULL,
"creator_trading_fee_claim_status" INT2 NOT NULL,
"fee_configuration_mode" INT2 NOT NULL,
"is_migrated" INT2 NOT NULL,
"pad" BYTEA NOT NULL,
"slot_offset_based_fees" JSONB NOT NULL,
"creator_trading_fee_receiver" BYTEA NOT NULL,
-- Account metadata
__pubkey BYTEA NOT NULL,
__slot NUMERIC(20),
PRIMARY KEY (__pubkey)
)"#).execute(connection).await?;
Ok(())
}
async fn down(
&self,
connection: &mut sqlx::PgConnection,
) -> Result<(), sqlx_migrator::error::Error> {
sqlx::query(r#"DROP TABLE IF EXISTS liquidity_pool_state_account"#)
.execute(connection)
.await?;
Ok(())
}
}