Skip to content

Commit

Permalink
Add auction database functions to orderbook and autopilot
Browse files Browse the repository at this point in the history
  • Loading branch information
vkgnosis committed Aug 10, 2022
1 parent 6c9e70a commit 5a7abc4
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 8 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/autopilot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ clap = { version = "3.1", features = ["derive", "env"] }
contracts = { path = "../contracts" }
database = { path = "../database" }
ethcontract = { version = "0.17.0", default-features = false }
futures = "0.3"
gas-estimation = { git = "https://github.com/cowprotocol/gas-estimation", tag = "v0.7.0", features = ["web3_"] }
global-metrics = { path = "../global-metrics" }
model = { path = "../model" }
number_conversions = { path = "../number_conversions" }
primitive-types = { version = "0.10" }
prometheus = "0.13"
prometheus-metric-storage = { git = "https://github.com/cowprotocol/prometheus-metric-storage" , tag = "v0.4.0" }
serde_json = "1.0"
shared= { path = "../shared" }
sqlx = { version = "0.6", default-features = false, features = ["runtime-tokio-native-tls"] }
tokio = { version = "1.15", features = ["macros", "rt-multi-thread", "sync", "time", "signal"] }
Expand Down
1 change: 1 addition & 0 deletions crates/autopilot/src/database.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod auction;
mod events;
mod quotes;

Expand Down
161 changes: 161 additions & 0 deletions crates/autopilot/src/database/auction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
use super::Postgres;
use anyhow::{anyhow, Context, Result};
use database::{
auction::AuctionId,
orders::{
BuyTokenDestination as DbBuyTokenDestination, OrderKind as DbOrderKind,
SellTokenSource as DbSellTokenSource, SigningScheme as DbSigningScheme,
},
solver_competition::SolverCompetitionId,
};
use futures::{StreamExt, TryStreamExt};
use model::{
app_id::AppId,
auction::Auction,
order::{
BuyTokenDestination, Order, OrderData, OrderKind, OrderMetadata, OrderStatus, OrderUid,
SellTokenSource,
},
signature::{Signature, SigningScheme},
};
use number_conversions::{big_decimal_to_big_uint, big_decimal_to_u256};
use primitive_types::H160;

pub struct SolvableOrders {
pub orders: Vec<Order>,
pub latest_settlement_block: u64,
}

impl Postgres {
pub async fn solvable_orders(&self, min_valid_to: u32) -> Result<SolvableOrders> {
let _timer = super::Metrics::get()
.database_queries
.with_label_values(&["solvable_orders"])
.start_timer();

let mut ex = self.0.begin().await?;
let orders = database::orders::solvable_orders(&mut ex, min_valid_to as i64)
.map(|result| match result {
Ok(order) => full_order_into_model_order(order),
Err(err) => Err(anyhow::Error::from(err)),
})
.try_collect::<Vec<_>>()
.await?;
let latest_settlement_block =
database::orders::latest_settlement_block(&mut ex).await? as u64;
Ok(SolvableOrders {
orders,
latest_settlement_block,
})
}

pub async fn replace_current_auction(&self, auction: &Auction) -> Result<AuctionId> {
let _timer = super::Metrics::get()
.database_queries
.with_label_values(&["save_auction"])
.start_timer();

let data = serde_json::to_value(&auction)?;
let mut ex = self.0.begin().await?;
database::auction::delete_all_auctions(&mut ex).await?;
let id = database::auction::save(&mut ex, &data).await?;
ex.commit().await?;
Ok(id)
}

pub async fn next_solver_competition(&self) -> Result<SolverCompetitionId> {
let _timer = super::Metrics::get()
.database_queries
.with_label_values(&["next_solver_competition"])
.start_timer();

let mut ex = self.0.acquire().await.map_err(anyhow::Error::from)?;
database::solver_competition::next_solver_competition(&mut ex)
.await
.context("failed to get next solver competition ID")
}
}

fn full_order_into_model_order(order: database::orders::FullOrder) -> Result<Order> {
let status = OrderStatus::Open;
let metadata = OrderMetadata {
creation_date: order.creation_timestamp,
owner: H160(order.owner.0),
uid: OrderUid(order.uid.0),
available_balance: Default::default(),
executed_buy_amount: big_decimal_to_big_uint(&order.sum_buy)
.context("executed buy amount is not an unsigned integer")?,
executed_sell_amount: big_decimal_to_big_uint(&order.sum_sell)
.context("executed sell amount is not an unsigned integer")?,
// Executed fee amounts and sell amounts before fees are capped by
// order's fee and sell amounts, and thus can always fit in a `U256`
// - as it is limited by the order format.
executed_sell_amount_before_fees: big_decimal_to_u256(&(order.sum_sell - &order.sum_fee))
.context(
"executed sell amount before fees does not fit in a u256",
)?,
executed_fee_amount: big_decimal_to_u256(&order.sum_fee)
.context("executed fee amount is not a valid u256")?,
invalidated: order.invalidated,
status,
settlement_contract: H160(order.settlement_contract.0),
full_fee_amount: big_decimal_to_u256(&order.full_fee_amount)
.ok_or_else(|| anyhow!("full_fee_amount is not U256"))?,
is_liquidity_order: order.is_liquidity_order,
};
let data = OrderData {
sell_token: H160(order.sell_token.0),
buy_token: H160(order.buy_token.0),
receiver: order.receiver.map(|address| H160(address.0)),
sell_amount: big_decimal_to_u256(&order.sell_amount)
.ok_or_else(|| anyhow!("sell_amount is not U256"))?,
buy_amount: big_decimal_to_u256(&order.buy_amount)
.ok_or_else(|| anyhow!("buy_amount is not U256"))?,
valid_to: order.valid_to.try_into().context("valid_to is not u32")?,
app_data: AppId(order.app_data.0),
fee_amount: big_decimal_to_u256(&order.fee_amount)
.ok_or_else(|| anyhow!("fee_amount is not U256"))?,
kind: order_kind_from(order.kind),
partially_fillable: order.partially_fillable,
sell_token_balance: sell_token_source_from(order.sell_token_balance),
buy_token_balance: buy_token_destination_from(order.buy_token_balance),
};
let signing_scheme = signing_scheme_from(order.signing_scheme);
let signature = Signature::from_bytes(signing_scheme, &order.signature)?;
Ok(Order {
metadata,
data,
signature,
})
}

pub fn order_kind_from(kind: DbOrderKind) -> OrderKind {
match kind {
DbOrderKind::Buy => OrderKind::Buy,
DbOrderKind::Sell => OrderKind::Sell,
}
}

fn sell_token_source_from(source: DbSellTokenSource) -> SellTokenSource {
match source {
DbSellTokenSource::Erc20 => SellTokenSource::Erc20,
DbSellTokenSource::Internal => SellTokenSource::Internal,
DbSellTokenSource::External => SellTokenSource::External,
}
}

fn buy_token_destination_from(destination: DbBuyTokenDestination) -> BuyTokenDestination {
match destination {
DbBuyTokenDestination::Erc20 => BuyTokenDestination::Erc20,
DbBuyTokenDestination::Internal => BuyTokenDestination::Internal,
}
}

fn signing_scheme_from(scheme: DbSigningScheme) -> SigningScheme {
match scheme {
DbSigningScheme::Eip712 => SigningScheme::Eip712,
DbSigningScheme::EthSign => SigningScheme::EthSign,
DbSigningScheme::Eip1271 => SigningScheme::Eip1271,
DbSigningScheme::PreSign => SigningScheme::PreSign,
}
}
19 changes: 12 additions & 7 deletions crates/database/src/auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,9 @@ LIMIT 1
sqlx::query_as(QUERY).fetch_optional(ex).await
}

pub async fn delete_other_than(ex: &mut PgConnection, id: AuctionId) -> Result<(), sqlx::Error> {
const QUERY: &str = r#"
DELETE FROM auctions
WHERE id != $1
;"#;
sqlx::query(QUERY).bind(id).execute(ex).await.map(|_| ())
pub async fn delete_all_auctions(ex: &mut PgConnection) -> Result<(), sqlx::Error> {
const QUERY: &str = "TRUNCATE auctions;";
sqlx::query(QUERY).execute(ex).await.map(|_| ())
}

#[cfg(test)]
Expand Down Expand Up @@ -57,8 +54,16 @@ mod tests {
assert_eq!(value, value_);
assert_eq!(id_, id);

delete_other_than(&mut db, id + 1).await.unwrap();
delete_all_auctions(&mut db).await.unwrap();
let result = load_most_recent(&mut db).await.unwrap();
assert!(result.is_none());

// id still increases after deletion
let value = JsonValue::Number(3.into());
let id_ = save(&mut db, &value).await.unwrap();
assert_eq!(id + 1, id_);
let (id, value_) = load_most_recent(&mut db).await.unwrap().unwrap();
assert_eq!(value, value_);
assert_eq!(id_, id);
}
}
2 changes: 1 addition & 1 deletion crates/orderbook/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ clap = { version = "3.1", features = ["derive", "env"] }
contracts = { path = "../contracts" }
database = { path = "../database" }
ethcontract = { version = "0.17.0", default-features = false }
futures = "0.3.19"
futures = "0.3"
gas-estimation = { git = "https://github.com/cowprotocol/gas-estimation", tag = "v0.7.0", features = ["web3_"] }
global-metrics = { path = "../global-metrics" }
hex = { version = "0.4", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions crates/orderbook/src/database.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod auctions;
pub mod orders;
pub mod quotes;
pub mod solver_competition;
Expand Down
19 changes: 19 additions & 0 deletions crates/orderbook/src/database/auctions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use anyhow::Result;
use model::auction::Auction;

impl super::Postgres {
pub async fn most_recent_auction(&self) -> Result<Option<Auction>> {
let _timer = super::Metrics::get()
.database_queries
.with_label_values(&["load_most_recent_auction"])
.start_timer();

let mut ex = self.pool.acquire().await?;
let (_auction_id, json) = match database::auction::load_most_recent(&mut ex).await? {
Some(inner) => inner,
None => return Ok(None),
};
let auction: Auction = serde_json::from_value(json)?;
Ok(Some(auction))
}
}

0 comments on commit 5a7abc4

Please sign in to comment.