use {
crate::types::{
Asset, ExpirySeries, HaltState, MarginParameters, PerpParameters, PricingParameters,
Product,
},
carbon_core::{
account::AccountMetadata,
postgres::{
metadata::AccountRowMetadata,
primitives::{Pubkey, U32, U8},
},
},
};
#[derive(sqlx::FromRow, Debug, Clone)]
pub struct ZetaGroupRow {
#[sqlx(flatten)]
pub account_metadata: AccountRowMetadata,
pub nonce: U8,
pub nonce_padding: Vec<u8>,
pub front_expiry_index: U8,
pub halt_state: sqlx::types::Json<HaltState>,
pub underlying_mint: Pubkey,
pub oracle: Pubkey,
pub greeks: Pubkey,
pub pricing_parameters: sqlx::types::Json<PricingParameters>,
pub margin_parameters: sqlx::types::Json<MarginParameters>,
pub margin_parameters_padding: Vec<u8>,
pub products: sqlx::types::Json<Vec<Product>>,
pub products_padding: sqlx::types::Json<Vec<Product>>,
pub perp: sqlx::types::Json<Product>,
pub expiry_series: sqlx::types::Json<Vec<ExpirySeries>>,
pub expiry_series_padding: sqlx::types::Json<Vec<ExpirySeries>>,
pub deprecated_padding: Vec<u8>,
pub asset: sqlx::types::Json<Asset>,
pub expiry_interval_seconds: U32,
pub new_expiry_threshold_seconds: U32,
pub perp_parameters: sqlx::types::Json<PerpParameters>,
pub perp_sync_queue: Pubkey,
pub oracle_backup_feed: Pubkey,
pub perps_only: bool,
pub flex_underlying: bool,
pub padding: Vec<u8>,
}
impl ZetaGroupRow {
pub fn from_parts(
source: crate::accounts::zeta_group::ZetaGroup,
metadata: AccountMetadata,
) -> Self {
Self {
account_metadata: metadata.into(),
nonce: source.nonce.into(),
nonce_padding: source.nonce_padding.to_vec(),
front_expiry_index: source.front_expiry_index.into(),
halt_state: sqlx::types::Json(source.halt_state),
underlying_mint: source.underlying_mint.into(),
oracle: source.oracle.into(),
greeks: source.greeks.into(),
pricing_parameters: sqlx::types::Json(source.pricing_parameters),
margin_parameters: sqlx::types::Json(source.margin_parameters),
margin_parameters_padding: source.margin_parameters_padding.to_vec(),
products: sqlx::types::Json(source.products.to_vec()),
products_padding: sqlx::types::Json(source.products_padding.to_vec()),
perp: sqlx::types::Json(source.perp),
expiry_series: sqlx::types::Json(source.expiry_series.to_vec()),
expiry_series_padding: sqlx::types::Json(source.expiry_series_padding.to_vec()),
deprecated_padding: source.deprecated_padding.to_vec(),
asset: sqlx::types::Json(source.asset),
expiry_interval_seconds: source.expiry_interval_seconds.into(),
new_expiry_threshold_seconds: source.new_expiry_threshold_seconds.into(),
perp_parameters: sqlx::types::Json(source.perp_parameters),
perp_sync_queue: source.perp_sync_queue.into(),
oracle_backup_feed: source.oracle_backup_feed.into(),
perps_only: source.perps_only,
flex_underlying: source.flex_underlying,
padding: source.padding.to_vec(),
}
}
}
impl TryFrom<ZetaGroupRow> for crate::accounts::zeta_group::ZetaGroup {
type Error = carbon_core::error::Error;
fn try_from(source: ZetaGroupRow) -> Result<Self, Self::Error> {
Ok(Self {
nonce: source.nonce.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
nonce_padding: source.nonce_padding.as_slice().try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert padding from postgres primitive: expected 2 bytes"
.to_string(),
)
})?,
front_expiry_index: source.front_expiry_index.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
halt_state: source.halt_state.0,
underlying_mint: *source.underlying_mint,
oracle: *source.oracle,
greeks: *source.greeks,
pricing_parameters: source.pricing_parameters.0,
margin_parameters: source.margin_parameters.0,
margin_parameters_padding: source
.margin_parameters_padding
.as_slice()
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert padding from postgres primitive: expected 104 bytes"
.to_string(),
)
})?,
products: source
.products
.0
.into_iter()
.collect::<Vec<_>>()
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
products_padding: source
.products_padding
.0
.into_iter()
.collect::<Vec<_>>()
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
perp: source.perp.0,
expiry_series: source
.expiry_series
.0
.into_iter()
.collect::<Vec<_>>()
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
expiry_series_padding: source
.expiry_series_padding
.0
.into_iter()
.collect::<Vec<_>>()
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
deprecated_padding: source
.deprecated_padding
.as_slice()
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert padding from postgres primitive: expected 8 bytes"
.to_string(),
)
})?,
asset: source.asset.0,
expiry_interval_seconds: source.expiry_interval_seconds.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
new_expiry_threshold_seconds: source.new_expiry_threshold_seconds.try_into().map_err(
|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
},
)?,
perp_parameters: source.perp_parameters.0,
perp_sync_queue: *source.perp_sync_queue,
oracle_backup_feed: *source.oracle_backup_feed,
perps_only: source.perps_only,
flex_underlying: source.flex_underlying,
padding: source.padding.as_slice().try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert padding from postgres primitive: expected 964 bytes"
.to_string(),
)
})?,
})
}
}
impl carbon_core::postgres::operations::Table for crate::accounts::zeta_group::ZetaGroup {
fn table() -> &'static str {
"zeta_group_account"
}
fn columns() -> Vec<&'static str> {
vec![
"__pubkey",
"__slot",
"nonce",
"nonce_padding",
"front_expiry_index",
"halt_state",
"underlying_mint",
"oracle",
"greeks",
"pricing_parameters",
"margin_parameters",
"margin_parameters_padding",
"products",
"products_padding",
"perp",
"expiry_series",
"expiry_series_padding",
"deprecated_padding",
"asset",
"expiry_interval_seconds",
"new_expiry_threshold_seconds",
"perp_parameters",
"perp_sync_queue",
"oracle_backup_feed",
"perps_only",
"flex_underlying",
"padding",
]
}
}
#[async_trait::async_trait]
impl carbon_core::postgres::operations::Insert for ZetaGroupRow {
async fn insert(&self, pool: &sqlx::PgPool) -> carbon_core::error::CarbonResult<()> {
sqlx::query(r#"
INSERT INTO zeta_group_account (
"nonce",
"nonce_padding",
"front_expiry_index",
"halt_state",
"underlying_mint",
"oracle",
"greeks",
"pricing_parameters",
"margin_parameters",
"margin_parameters_padding",
"products",
"products_padding",
"perp",
"expiry_series",
"expiry_series_padding",
"deprecated_padding",
"asset",
"expiry_interval_seconds",
"new_expiry_threshold_seconds",
"perp_parameters",
"perp_sync_queue",
"oracle_backup_feed",
"perps_only",
"flex_underlying",
"padding",
__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
)"#)
.bind(self.nonce)
.bind(&self.nonce_padding)
.bind(self.front_expiry_index)
.bind(&self.halt_state)
.bind(self.underlying_mint)
.bind(self.oracle)
.bind(self.greeks)
.bind(&self.pricing_parameters)
.bind(&self.margin_parameters)
.bind(&self.margin_parameters_padding)
.bind(&self.products)
.bind(&self.products_padding)
.bind(&self.perp)
.bind(&self.expiry_series)
.bind(&self.expiry_series_padding)
.bind(&self.deprecated_padding)
.bind(&self.asset)
.bind(self.expiry_interval_seconds)
.bind(self.new_expiry_threshold_seconds)
.bind(&self.perp_parameters)
.bind(self.perp_sync_queue)
.bind(self.oracle_backup_feed)
.bind(self.perps_only)
.bind(self.flex_underlying)
.bind(&self.padding)
.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 ZetaGroupRow {
async fn upsert(&self, pool: &sqlx::PgPool) -> carbon_core::error::CarbonResult<()> {
sqlx::query(r#"INSERT INTO zeta_group_account (
"nonce",
"nonce_padding",
"front_expiry_index",
"halt_state",
"underlying_mint",
"oracle",
"greeks",
"pricing_parameters",
"margin_parameters",
"margin_parameters_padding",
"products",
"products_padding",
"perp",
"expiry_series",
"expiry_series_padding",
"deprecated_padding",
"asset",
"expiry_interval_seconds",
"new_expiry_threshold_seconds",
"perp_parameters",
"perp_sync_queue",
"oracle_backup_feed",
"perps_only",
"flex_underlying",
"padding",
__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
) ON CONFLICT (
__pubkey
) DO UPDATE SET
"nonce" = EXCLUDED."nonce",
"nonce_padding" = EXCLUDED."nonce_padding",
"front_expiry_index" = EXCLUDED."front_expiry_index",
"halt_state" = EXCLUDED."halt_state",
"underlying_mint" = EXCLUDED."underlying_mint",
"oracle" = EXCLUDED."oracle",
"greeks" = EXCLUDED."greeks",
"pricing_parameters" = EXCLUDED."pricing_parameters",
"margin_parameters" = EXCLUDED."margin_parameters",
"margin_parameters_padding" = EXCLUDED."margin_parameters_padding",
"products" = EXCLUDED."products",
"products_padding" = EXCLUDED."products_padding",
"perp" = EXCLUDED."perp",
"expiry_series" = EXCLUDED."expiry_series",
"expiry_series_padding" = EXCLUDED."expiry_series_padding",
"deprecated_padding" = EXCLUDED."deprecated_padding",
"asset" = EXCLUDED."asset",
"expiry_interval_seconds" = EXCLUDED."expiry_interval_seconds",
"new_expiry_threshold_seconds" = EXCLUDED."new_expiry_threshold_seconds",
"perp_parameters" = EXCLUDED."perp_parameters",
"perp_sync_queue" = EXCLUDED."perp_sync_queue",
"oracle_backup_feed" = EXCLUDED."oracle_backup_feed",
"perps_only" = EXCLUDED."perps_only",
"flex_underlying" = EXCLUDED."flex_underlying",
"padding" = EXCLUDED."padding",
__slot = EXCLUDED.__slot
"#)
.bind(self.nonce)
.bind(&self.nonce_padding)
.bind(self.front_expiry_index)
.bind(&self.halt_state)
.bind(self.underlying_mint)
.bind(self.oracle)
.bind(self.greeks)
.bind(&self.pricing_parameters)
.bind(&self.margin_parameters)
.bind(&self.margin_parameters_padding)
.bind(&self.products)
.bind(&self.products_padding)
.bind(&self.perp)
.bind(&self.expiry_series)
.bind(&self.expiry_series_padding)
.bind(&self.deprecated_padding)
.bind(&self.asset)
.bind(self.expiry_interval_seconds)
.bind(self.new_expiry_threshold_seconds)
.bind(&self.perp_parameters)
.bind(self.perp_sync_queue)
.bind(self.oracle_backup_feed)
.bind(self.perps_only)
.bind(self.flex_underlying)
.bind(&self.padding)
.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 ZetaGroupRow {
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 zeta_group_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 ZetaGroupRow {
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 zeta_group_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 ZetaGroupMigrationOperation;
#[async_trait::async_trait]
impl sqlx_migrator::Operation<sqlx::Postgres> for ZetaGroupMigrationOperation {
async fn up(
&self,
connection: &mut sqlx::PgConnection,
) -> Result<(), sqlx_migrator::error::Error> {
sqlx::query(
r#"CREATE TABLE IF NOT EXISTS zeta_group_account (
-- Account data
"nonce" INT2 NOT NULL,
"nonce_padding" BYTEA NOT NULL,
"front_expiry_index" INT2 NOT NULL,
"halt_state" JSONB NOT NULL,
"underlying_mint" BYTEA NOT NULL,
"oracle" BYTEA NOT NULL,
"greeks" BYTEA NOT NULL,
"pricing_parameters" JSONB NOT NULL,
"margin_parameters" JSONB NOT NULL,
"margin_parameters_padding" BYTEA NOT NULL,
"products" JSONB NOT NULL,
"products_padding" JSONB NOT NULL,
"perp" JSONB NOT NULL,
"expiry_series" JSONB NOT NULL,
"expiry_series_padding" JSONB NOT NULL,
"deprecated_padding" BYTEA NOT NULL,
"asset" JSONB NOT NULL,
"expiry_interval_seconds" INT8 NOT NULL,
"new_expiry_threshold_seconds" INT8 NOT NULL,
"perp_parameters" JSONB NOT NULL,
"perp_sync_queue" BYTEA NOT NULL,
"oracle_backup_feed" BYTEA NOT NULL,
"perps_only" BOOLEAN NOT NULL,
"flex_underlying" BOOLEAN NOT NULL,
"padding" 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 zeta_group_account"#)
.execute(connection)
.await?;
Ok(())
}
}