use {
crate::types::{FeeStateCache, GroupRateLimiter, PanicStateCache, WithdrawWindowCache},
carbon_core::{
account::AccountMetadata,
postgres::{
metadata::AccountRowMetadata,
primitives::{Pubkey, U16, U32, U64},
},
},
};
#[derive(sqlx::FromRow, Debug, Clone)]
pub struct MarginfiGroupRow {
#[sqlx(flatten)]
pub account_metadata: AccountRowMetadata,
pub admin: Pubkey,
pub group_flags: U64,
pub fee_state_cache: sqlx::types::Json<FeeStateCache>,
pub banks: U16,
pub pad0: Vec<u8>,
pub emode_admin: Pubkey,
pub delegate_curve_admin: Pubkey,
pub delegate_limit_admin: Pubkey,
pub delegate_emissions_admin: Pubkey,
pub panic_state_cache: sqlx::types::Json<PanicStateCache>,
pub deleverage_withdraw_window_cache: sqlx::types::Json<WithdrawWindowCache>,
pub risk_admin: Pubkey,
pub metadata_admin: Pubkey,
pub emode_max_init_leverage: U32,
pub emode_max_maint_leverage: U32,
pub padding: Vec<u8>,
pub rate_limiter: sqlx::types::Json<GroupRateLimiter>,
pub rate_limiter_last_admin_update_slot: U64,
pub rate_limiter_last_admin_update_seq: U64,
pub deleverage_withdraw_last_admin_update_slot: U64,
pub deleverage_withdraw_last_admin_update_seq: U64,
pub delegate_flow_admin: Pubkey,
pub padding0: sqlx::types::Json<Vec<Vec<U64>>>,
pub padding1: sqlx::types::Json<Vec<Vec<U64>>>,
}
impl MarginfiGroupRow {
pub fn from_parts(
source: crate::accounts::marginfi_group::MarginfiGroup,
metadata: AccountMetadata,
) -> Self {
Self {
account_metadata: metadata.into(),
admin: source.admin.into(),
group_flags: source.group_flags.into(),
fee_state_cache: sqlx::types::Json(source.fee_state_cache),
banks: source.banks.into(),
pad0: source.pad0.to_vec(),
emode_admin: source.emode_admin.into(),
delegate_curve_admin: source.delegate_curve_admin.into(),
delegate_limit_admin: source.delegate_limit_admin.into(),
delegate_emissions_admin: source.delegate_emissions_admin.into(),
panic_state_cache: sqlx::types::Json(source.panic_state_cache),
deleverage_withdraw_window_cache: sqlx::types::Json(
source.deleverage_withdraw_window_cache,
),
risk_admin: source.risk_admin.into(),
metadata_admin: source.metadata_admin.into(),
emode_max_init_leverage: source.emode_max_init_leverage.into(),
emode_max_maint_leverage: source.emode_max_maint_leverage.into(),
padding: source.padding.to_vec(),
rate_limiter: sqlx::types::Json(source.rate_limiter),
rate_limiter_last_admin_update_slot: source.rate_limiter_last_admin_update_slot.into(),
rate_limiter_last_admin_update_seq: source.rate_limiter_last_admin_update_seq.into(),
deleverage_withdraw_last_admin_update_slot: source
.deleverage_withdraw_last_admin_update_slot
.into(),
deleverage_withdraw_last_admin_update_seq: source
.deleverage_withdraw_last_admin_update_seq
.into(),
delegate_flow_admin: source.delegate_flow_admin.into(),
padding0: sqlx::types::Json(
source
.padding0
.into_iter()
.map(|element| element.into_iter().map(|element| element.into()).collect())
.collect(),
),
padding1: sqlx::types::Json(
source
.padding1
.into_iter()
.map(|element| element.into_iter().map(|element| element.into()).collect())
.collect(),
),
}
}
}
impl TryFrom<MarginfiGroupRow> for crate::accounts::marginfi_group::MarginfiGroup {
type Error = carbon_core::error::Error;
fn try_from(source: MarginfiGroupRow) -> Result<Self, Self::Error> {
Ok(Self {
admin: *source.admin,
group_flags: *source.group_flags,
fee_state_cache: source.fee_state_cache.0,
banks: source.banks.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
pad0: source.pad0.as_slice().try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert padding from postgres primitive: expected 6 bytes"
.to_string(),
)
})?,
emode_admin: *source.emode_admin,
delegate_curve_admin: *source.delegate_curve_admin,
delegate_limit_admin: *source.delegate_limit_admin,
delegate_emissions_admin: *source.delegate_emissions_admin,
panic_state_cache: source.panic_state_cache.0,
deleverage_withdraw_window_cache: source.deleverage_withdraw_window_cache.0,
risk_admin: *source.risk_admin,
metadata_admin: *source.metadata_admin,
emode_max_init_leverage: source.emode_max_init_leverage.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
emode_max_maint_leverage: source.emode_max_maint_leverage.try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
padding: source.padding.as_slice().try_into().map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert padding from postgres primitive: expected 8 bytes"
.to_string(),
)
})?,
rate_limiter: source.rate_limiter.0,
rate_limiter_last_admin_update_slot: *source.rate_limiter_last_admin_update_slot,
rate_limiter_last_admin_update_seq: *source.rate_limiter_last_admin_update_seq,
deleverage_withdraw_last_admin_update_slot: *source
.deleverage_withdraw_last_admin_update_slot,
deleverage_withdraw_last_admin_update_seq: *source
.deleverage_withdraw_last_admin_update_seq,
delegate_flow_admin: *source.delegate_flow_admin,
padding0: source
.padding0
.0
.into_iter()
.map(|element| {
element
.into_iter()
.map(|element| Ok(*element))
.collect::<Result<Vec<_>, carbon_core::error::Error>>()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to collect array elements".to_string(),
)
})?
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert array element to primitive".to_string(),
)
})
})
.collect::<Result<Vec<_>, carbon_core::error::Error>>()?
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
padding1: source
.padding1
.0
.into_iter()
.map(|element| {
element
.into_iter()
.map(|element| Ok(*element))
.collect::<Result<Vec<_>, carbon_core::error::Error>>()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to collect array elements".to_string(),
)
})?
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert array element to primitive".to_string(),
)
})
})
.collect::<Result<Vec<_>, carbon_core::error::Error>>()?
.try_into()
.map_err(|_| {
carbon_core::error::Error::Custom(
"Failed to convert value from postgres primitive".to_string(),
)
})?,
})
}
}
impl carbon_core::postgres::operations::Table for crate::accounts::marginfi_group::MarginfiGroup {
fn table() -> &'static str {
"marginfi_group_account"
}
fn columns() -> Vec<&'static str> {
vec![
"__pubkey",
"__slot",
"admin",
"group_flags",
"fee_state_cache",
"banks",
"pad0",
"emode_admin",
"delegate_curve_admin",
"delegate_limit_admin",
"delegate_emissions_admin",
"panic_state_cache",
"deleverage_withdraw_window_cache",
"risk_admin",
"metadata_admin",
"emode_max_init_leverage",
"emode_max_maint_leverage",
"padding",
"rate_limiter",
"rate_limiter_last_admin_update_slot",
"rate_limiter_last_admin_update_seq",
"deleverage_withdraw_last_admin_update_slot",
"deleverage_withdraw_last_admin_update_seq",
"delegate_flow_admin",
"padding0",
"padding1",
]
}
}
#[async_trait::async_trait]
impl carbon_core::postgres::operations::Insert for MarginfiGroupRow {
async fn insert(&self, pool: &sqlx::PgPool) -> carbon_core::error::CarbonResult<()> {
sqlx::query(r#"
INSERT INTO marginfi_group_account (
"admin",
"group_flags",
"fee_state_cache",
"banks",
"pad0",
"emode_admin",
"delegate_curve_admin",
"delegate_limit_admin",
"delegate_emissions_admin",
"panic_state_cache",
"deleverage_withdraw_window_cache",
"risk_admin",
"metadata_admin",
"emode_max_init_leverage",
"emode_max_maint_leverage",
"padding",
"rate_limiter",
"rate_limiter_last_admin_update_slot",
"rate_limiter_last_admin_update_seq",
"deleverage_withdraw_last_admin_update_slot",
"deleverage_withdraw_last_admin_update_seq",
"delegate_flow_admin",
"padding0",
"padding1",
__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
)"#)
.bind(self.admin)
.bind(&self.group_flags)
.bind(&self.fee_state_cache)
.bind(self.banks)
.bind(&self.pad0)
.bind(self.emode_admin)
.bind(self.delegate_curve_admin)
.bind(self.delegate_limit_admin)
.bind(self.delegate_emissions_admin)
.bind(&self.panic_state_cache)
.bind(&self.deleverage_withdraw_window_cache)
.bind(self.risk_admin)
.bind(self.metadata_admin)
.bind(self.emode_max_init_leverage)
.bind(self.emode_max_maint_leverage)
.bind(&self.padding)
.bind(&self.rate_limiter)
.bind(&self.rate_limiter_last_admin_update_slot)
.bind(&self.rate_limiter_last_admin_update_seq)
.bind(&self.deleverage_withdraw_last_admin_update_slot)
.bind(&self.deleverage_withdraw_last_admin_update_seq)
.bind(self.delegate_flow_admin)
.bind(&self.padding0)
.bind(&self.padding1)
.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 MarginfiGroupRow {
async fn upsert(&self, pool: &sqlx::PgPool) -> carbon_core::error::CarbonResult<()> {
sqlx::query(r#"INSERT INTO marginfi_group_account (
"admin",
"group_flags",
"fee_state_cache",
"banks",
"pad0",
"emode_admin",
"delegate_curve_admin",
"delegate_limit_admin",
"delegate_emissions_admin",
"panic_state_cache",
"deleverage_withdraw_window_cache",
"risk_admin",
"metadata_admin",
"emode_max_init_leverage",
"emode_max_maint_leverage",
"padding",
"rate_limiter",
"rate_limiter_last_admin_update_slot",
"rate_limiter_last_admin_update_seq",
"deleverage_withdraw_last_admin_update_slot",
"deleverage_withdraw_last_admin_update_seq",
"delegate_flow_admin",
"padding0",
"padding1",
__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
) ON CONFLICT (
__pubkey
) DO UPDATE SET
"admin" = EXCLUDED."admin",
"group_flags" = EXCLUDED."group_flags",
"fee_state_cache" = EXCLUDED."fee_state_cache",
"banks" = EXCLUDED."banks",
"pad0" = EXCLUDED."pad0",
"emode_admin" = EXCLUDED."emode_admin",
"delegate_curve_admin" = EXCLUDED."delegate_curve_admin",
"delegate_limit_admin" = EXCLUDED."delegate_limit_admin",
"delegate_emissions_admin" = EXCLUDED."delegate_emissions_admin",
"panic_state_cache" = EXCLUDED."panic_state_cache",
"deleverage_withdraw_window_cache" = EXCLUDED."deleverage_withdraw_window_cache",
"risk_admin" = EXCLUDED."risk_admin",
"metadata_admin" = EXCLUDED."metadata_admin",
"emode_max_init_leverage" = EXCLUDED."emode_max_init_leverage",
"emode_max_maint_leverage" = EXCLUDED."emode_max_maint_leverage",
"padding" = EXCLUDED."padding",
"rate_limiter" = EXCLUDED."rate_limiter",
"rate_limiter_last_admin_update_slot" = EXCLUDED."rate_limiter_last_admin_update_slot",
"rate_limiter_last_admin_update_seq" = EXCLUDED."rate_limiter_last_admin_update_seq",
"deleverage_withdraw_last_admin_update_slot" = EXCLUDED."deleverage_withdraw_last_admin_update_slot",
"deleverage_withdraw_last_admin_update_seq" = EXCLUDED."deleverage_withdraw_last_admin_update_seq",
"delegate_flow_admin" = EXCLUDED."delegate_flow_admin",
"padding0" = EXCLUDED."padding0",
"padding1" = EXCLUDED."padding1",
__slot = EXCLUDED.__slot
"#)
.bind(self.admin)
.bind(&self.group_flags)
.bind(&self.fee_state_cache)
.bind(self.banks)
.bind(&self.pad0)
.bind(self.emode_admin)
.bind(self.delegate_curve_admin)
.bind(self.delegate_limit_admin)
.bind(self.delegate_emissions_admin)
.bind(&self.panic_state_cache)
.bind(&self.deleverage_withdraw_window_cache)
.bind(self.risk_admin)
.bind(self.metadata_admin)
.bind(self.emode_max_init_leverage)
.bind(self.emode_max_maint_leverage)
.bind(&self.padding)
.bind(&self.rate_limiter)
.bind(&self.rate_limiter_last_admin_update_slot)
.bind(&self.rate_limiter_last_admin_update_seq)
.bind(&self.deleverage_withdraw_last_admin_update_slot)
.bind(&self.deleverage_withdraw_last_admin_update_seq)
.bind(self.delegate_flow_admin)
.bind(&self.padding0)
.bind(&self.padding1)
.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 MarginfiGroupRow {
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 marginfi_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 MarginfiGroupRow {
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 marginfi_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 MarginfiGroupMigrationOperation;
#[async_trait::async_trait]
impl sqlx_migrator::Operation<sqlx::Postgres> for MarginfiGroupMigrationOperation {
async fn up(
&self,
connection: &mut sqlx::PgConnection,
) -> Result<(), sqlx_migrator::error::Error> {
sqlx::query(
r#"CREATE TABLE IF NOT EXISTS marginfi_group_account (
-- Account data
"admin" BYTEA NOT NULL,
"group_flags" NUMERIC(20) NOT NULL,
"fee_state_cache" JSONB NOT NULL,
"banks" INT4 NOT NULL,
"pad0" BYTEA NOT NULL,
"emode_admin" BYTEA NOT NULL,
"delegate_curve_admin" BYTEA NOT NULL,
"delegate_limit_admin" BYTEA NOT NULL,
"delegate_emissions_admin" BYTEA NOT NULL,
"panic_state_cache" JSONB NOT NULL,
"deleverage_withdraw_window_cache" JSONB NOT NULL,
"risk_admin" BYTEA NOT NULL,
"metadata_admin" BYTEA NOT NULL,
"emode_max_init_leverage" INT8 NOT NULL,
"emode_max_maint_leverage" INT8 NOT NULL,
"padding" BYTEA NOT NULL,
"rate_limiter" JSONB NOT NULL,
"rate_limiter_last_admin_update_slot" NUMERIC(20) NOT NULL,
"rate_limiter_last_admin_update_seq" NUMERIC(20) NOT NULL,
"deleverage_withdraw_last_admin_update_slot" NUMERIC(20) NOT NULL,
"deleverage_withdraw_last_admin_update_seq" NUMERIC(20) NOT NULL,
"delegate_flow_admin" BYTEA NOT NULL,
"padding0" JSONB NOT NULL,
"padding1" JSONB 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 marginfi_group_account"#)
.execute(connection)
.await?;
Ok(())
}
}