use {
crate::types::{FixedPoint, Product, Token},
carbon_core::{
account::AccountMetadata,
postgres::{
metadata::AccountRowMetadata,
primitives::{Pubkey, U64, U8},
},
},
};
#[derive(sqlx::FromRow, Debug, Clone)]
pub struct PoolRow {
#[sqlx(flatten)]
pub account_metadata: AccountRowMetadata,
pub token_x: Pubkey,
pub token_y: Pubkey,
pub pool_x_account: Pubkey,
pub pool_y_account: Pubkey,
pub admin: Pubkey,
pub project_owner: Pubkey,
pub token_x_reserve: sqlx::types::Json<Token>,
pub token_y_reserve: sqlx::types::Json<Token>,
pub self_shares: sqlx::types::Json<Token>,
pub all_shares: sqlx::types::Json<Token>,
pub buyback_amount_x: sqlx::types::Json<Token>,
pub buyback_amount_y: sqlx::types::Json<Token>,
pub project_amount_x: sqlx::types::Json<Token>,
pub project_amount_y: sqlx::types::Json<Token>,
pub mercanti_amount_x: sqlx::types::Json<Token>,
pub mercanti_amount_y: sqlx::types::Json<Token>,
pub lp_accumulator_x: sqlx::types::Json<FixedPoint>,
pub lp_accumulator_y: sqlx::types::Json<FixedPoint>,
pub const_k: sqlx::types::Json<Product>,
pub price: sqlx::types::Json<FixedPoint>,
pub lp_fee: sqlx::types::Json<FixedPoint>,
pub buyback_fee: sqlx::types::Json<FixedPoint>,
pub project_fee: sqlx::types::Json<FixedPoint>,
pub mercanti_fee: sqlx::types::Json<FixedPoint>,
pub farm_count: U64,
pub bump: U8,
}
impl PoolRow {
pub fn from_parts(source: crate::accounts::pool::Pool, metadata: AccountMetadata) -> Self {
Self {
account_metadata: metadata.into(),
token_x: source.token_x.into(),
token_y: source.token_y.into(),
pool_x_account: source.pool_x_account.into(),
pool_y_account: source.pool_y_account.into(),
admin: source.admin.into(),
project_owner: source.project_owner.into(),
token_x_reserve: sqlx::types::Json(source.token_x_reserve),
token_y_reserve: sqlx::types::Json(source.token_y_reserve),
self_shares: sqlx::types::Json(source.self_shares),
all_shares: sqlx::types::Json(source.all_shares),
buyback_amount_x: sqlx::types::Json(source.buyback_amount_x),
buyback_amount_y: sqlx::types::Json(source.buyback_amount_y),
project_amount_x: sqlx::types::Json(source.project_amount_x),
project_amount_y: sqlx::types::Json(source.project_amount_y),
mercanti_amount_x: sqlx::types::Json(source.mercanti_amount_x),
mercanti_amount_y: sqlx::types::Json(source.mercanti_amount_y),
lp_accumulator_x: sqlx::types::Json(source.lp_accumulator_x),
lp_accumulator_y: sqlx::types::Json(source.lp_accumulator_y),
const_k: sqlx::types::Json(source.const_k),
price: sqlx::types::Json(source.price),
lp_fee: sqlx::types::Json(source.lp_fee),
buyback_fee: sqlx::types::Json(source.buyback_fee),
project_fee: sqlx::types::Json(source.project_fee),
mercanti_fee: sqlx::types::Json(source.mercanti_fee),
farm_count: source.farm_count.into(),
bump: source.bump.into(),
}
}
}
impl TryFrom<PoolRow> for crate::accounts::pool::Pool {
type Error = carbon_core::error::Error;
fn try_from(source: PoolRow) -> Result<Self, Self::Error> {
Ok(Self {
token_x: *source.token_x,
token_y: *source.token_y,
pool_x_account: *source.pool_x_account,
pool_y_account: *source.pool_y_account,
admin: *source.admin,
project_owner: *source.project_owner,
token_x_reserve: source.token_x_reserve.0,
token_y_reserve: source.token_y_reserve.0,
self_shares: source.self_shares.0,
all_shares: source.all_shares.0,
buyback_amount_x: source.buyback_amount_x.0,
buyback_amount_y: source.buyback_amount_y.0,
project_amount_x: source.project_amount_x.0,
project_amount_y: source.project_amount_y.0,
mercanti_amount_x: source.mercanti_amount_x.0,
mercanti_amount_y: source.mercanti_amount_y.0,
lp_accumulator_x: source.lp_accumulator_x.0,
lp_accumulator_y: source.lp_accumulator_y.0,
const_k: source.const_k.0,
price: source.price.0,
lp_fee: source.lp_fee.0,
buyback_fee: source.buyback_fee.0,
project_fee: source.project_fee.0,
mercanti_fee: source.mercanti_fee.0,
farm_count: *source.farm_count,
bump: source.bump.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::pool::Pool {
fn table() -> &'static str {
"pool_account"
}
fn columns() -> Vec<&'static str> {
vec![
"__pubkey",
"__slot",
"token_x",
"token_y",
"pool_x_account",
"pool_y_account",
"admin",
"project_owner",
"token_x_reserve",
"token_y_reserve",
"self_shares",
"all_shares",
"buyback_amount_x",
"buyback_amount_y",
"project_amount_x",
"project_amount_y",
"mercanti_amount_x",
"mercanti_amount_y",
"lp_accumulator_x",
"lp_accumulator_y",
"const_k",
"price",
"lp_fee",
"buyback_fee",
"project_fee",
"mercanti_fee",
"farm_count",
"bump",
]
}
}
#[async_trait::async_trait]
impl carbon_core::postgres::operations::Insert for PoolRow {
async fn insert(&self, pool: &sqlx::PgPool) -> carbon_core::error::CarbonResult<()> {
sqlx::query(r#"
INSERT INTO pool_account (
"token_x",
"token_y",
"pool_x_account",
"pool_y_account",
"admin",
"project_owner",
"token_x_reserve",
"token_y_reserve",
"self_shares",
"all_shares",
"buyback_amount_x",
"buyback_amount_y",
"project_amount_x",
"project_amount_y",
"mercanti_amount_x",
"mercanti_amount_y",
"lp_accumulator_x",
"lp_accumulator_y",
"const_k",
"price",
"lp_fee",
"buyback_fee",
"project_fee",
"mercanti_fee",
"farm_count",
"bump",
__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
)"#)
.bind(self.token_x)
.bind(self.token_y)
.bind(self.pool_x_account)
.bind(self.pool_y_account)
.bind(self.admin)
.bind(self.project_owner)
.bind(&self.token_x_reserve)
.bind(&self.token_y_reserve)
.bind(&self.self_shares)
.bind(&self.all_shares)
.bind(&self.buyback_amount_x)
.bind(&self.buyback_amount_y)
.bind(&self.project_amount_x)
.bind(&self.project_amount_y)
.bind(&self.mercanti_amount_x)
.bind(&self.mercanti_amount_y)
.bind(&self.lp_accumulator_x)
.bind(&self.lp_accumulator_y)
.bind(&self.const_k)
.bind(&self.price)
.bind(&self.lp_fee)
.bind(&self.buyback_fee)
.bind(&self.project_fee)
.bind(&self.mercanti_fee)
.bind(&self.farm_count)
.bind(self.bump)
.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 PoolRow {
async fn upsert(&self, pool: &sqlx::PgPool) -> carbon_core::error::CarbonResult<()> {
sqlx::query(r#"INSERT INTO pool_account (
"token_x",
"token_y",
"pool_x_account",
"pool_y_account",
"admin",
"project_owner",
"token_x_reserve",
"token_y_reserve",
"self_shares",
"all_shares",
"buyback_amount_x",
"buyback_amount_y",
"project_amount_x",
"project_amount_y",
"mercanti_amount_x",
"mercanti_amount_y",
"lp_accumulator_x",
"lp_accumulator_y",
"const_k",
"price",
"lp_fee",
"buyback_fee",
"project_fee",
"mercanti_fee",
"farm_count",
"bump",
__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
) ON CONFLICT (
__pubkey
) DO UPDATE SET
"token_x" = EXCLUDED."token_x",
"token_y" = EXCLUDED."token_y",
"pool_x_account" = EXCLUDED."pool_x_account",
"pool_y_account" = EXCLUDED."pool_y_account",
"admin" = EXCLUDED."admin",
"project_owner" = EXCLUDED."project_owner",
"token_x_reserve" = EXCLUDED."token_x_reserve",
"token_y_reserve" = EXCLUDED."token_y_reserve",
"self_shares" = EXCLUDED."self_shares",
"all_shares" = EXCLUDED."all_shares",
"buyback_amount_x" = EXCLUDED."buyback_amount_x",
"buyback_amount_y" = EXCLUDED."buyback_amount_y",
"project_amount_x" = EXCLUDED."project_amount_x",
"project_amount_y" = EXCLUDED."project_amount_y",
"mercanti_amount_x" = EXCLUDED."mercanti_amount_x",
"mercanti_amount_y" = EXCLUDED."mercanti_amount_y",
"lp_accumulator_x" = EXCLUDED."lp_accumulator_x",
"lp_accumulator_y" = EXCLUDED."lp_accumulator_y",
"const_k" = EXCLUDED."const_k",
"price" = EXCLUDED."price",
"lp_fee" = EXCLUDED."lp_fee",
"buyback_fee" = EXCLUDED."buyback_fee",
"project_fee" = EXCLUDED."project_fee",
"mercanti_fee" = EXCLUDED."mercanti_fee",
"farm_count" = EXCLUDED."farm_count",
"bump" = EXCLUDED."bump",
__slot = EXCLUDED.__slot
"#)
.bind(self.token_x)
.bind(self.token_y)
.bind(self.pool_x_account)
.bind(self.pool_y_account)
.bind(self.admin)
.bind(self.project_owner)
.bind(&self.token_x_reserve)
.bind(&self.token_y_reserve)
.bind(&self.self_shares)
.bind(&self.all_shares)
.bind(&self.buyback_amount_x)
.bind(&self.buyback_amount_y)
.bind(&self.project_amount_x)
.bind(&self.project_amount_y)
.bind(&self.mercanti_amount_x)
.bind(&self.mercanti_amount_y)
.bind(&self.lp_accumulator_x)
.bind(&self.lp_accumulator_y)
.bind(&self.const_k)
.bind(&self.price)
.bind(&self.lp_fee)
.bind(&self.buyback_fee)
.bind(&self.project_fee)
.bind(&self.mercanti_fee)
.bind(&self.farm_count)
.bind(self.bump)
.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 PoolRow {
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 pool_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 PoolRow {
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 pool_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 PoolMigrationOperation;
#[async_trait::async_trait]
impl sqlx_migrator::Operation<sqlx::Postgres> for PoolMigrationOperation {
async fn up(
&self,
connection: &mut sqlx::PgConnection,
) -> Result<(), sqlx_migrator::error::Error> {
sqlx::query(
r#"CREATE TABLE IF NOT EXISTS pool_account (
-- Account data
"token_x" BYTEA NOT NULL,
"token_y" BYTEA NOT NULL,
"pool_x_account" BYTEA NOT NULL,
"pool_y_account" BYTEA NOT NULL,
"admin" BYTEA NOT NULL,
"project_owner" BYTEA NOT NULL,
"token_x_reserve" JSONB NOT NULL,
"token_y_reserve" JSONB NOT NULL,
"self_shares" JSONB NOT NULL,
"all_shares" JSONB NOT NULL,
"buyback_amount_x" JSONB NOT NULL,
"buyback_amount_y" JSONB NOT NULL,
"project_amount_x" JSONB NOT NULL,
"project_amount_y" JSONB NOT NULL,
"mercanti_amount_x" JSONB NOT NULL,
"mercanti_amount_y" JSONB NOT NULL,
"lp_accumulator_x" JSONB NOT NULL,
"lp_accumulator_y" JSONB NOT NULL,
"const_k" JSONB NOT NULL,
"price" JSONB NOT NULL,
"lp_fee" JSONB NOT NULL,
"buyback_fee" JSONB NOT NULL,
"project_fee" JSONB NOT NULL,
"mercanti_fee" JSONB NOT NULL,
"farm_count" NUMERIC(20) NOT NULL,
"bump" INT2 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 pool_account"#)
.execute(connection)
.await?;
Ok(())
}
}