Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/autopilot/src/database/auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl Postgres {
.execute(ex.deref_mut())
.await?;
let orders: HashMap<domain::OrderUid, Arc<Order>> =
database::orders::solvable_orders(&mut ex, i64::from(min_valid_to))
database::orders::solvable_orders(&mut ex, i64::from(min_valid_to), start.timestamp())
.map(|result| match result {
Ok(order) => full_order_into_model_order(order)
.map(|order| (domain::OrderUid(order.metadata.uid.0), Arc::new(order))),
Expand Down
111 changes: 67 additions & 44 deletions crates/autopilot/src/database/onchain_order_events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use {
rpc::types::Log,
},
anyhow::{Context, Result, anyhow, bail},
app_data::AppDataHash,
app_data::{AppDataHash, ProtocolAppData},
chrono::{TimeZone, Utc},
contracts::{
CoWSwapOnchainOrders::CoWSwapOnchainOrders::{
Expand Down Expand Up @@ -318,7 +318,7 @@ impl<T: Send + Sync + Clone, W: Send + Sync> OnchainOrderParser<T, W> {
.collect();
let invalidation_events = get_invalidation_events(events)?;
let invalided_order_uids = extract_invalidated_order_uids(invalidation_events)?;
let (custom_onchain_data, quotes, broadcasted_order_data, orders, tx_hashes) = self
let (custom_onchain_data, quotes, broadcasted_order_data, mut orders, tx_hashes) = self
.extract_custom_and_general_order_data(order_placement_events)
.await?;

Expand Down Expand Up @@ -356,9 +356,9 @@ impl<T: Send + Sync + Clone, W: Send + Sync> OnchainOrderParser<T, W> {
.await
.context("appending quotes for onchain orders failed")?;

insert_order_hooks(transaction, &orders, &self.trampoline)
handle_app_data(transaction, &mut orders, &self.trampoline)
.await
.context("failed to insert hooks")?;
.context("failed to handle app data")?;

database::orders::insert_orders_and_ignore_conflicts(transaction, orders.as_slice())
.await
Expand Down Expand Up @@ -628,6 +628,9 @@ fn convert_onchain_order_placement(
true => OrderClass::Limit,
false => OrderClass::Market,
},
// Backfilled from the order's app-data in `handle_app_data` before the
// order is persisted; the full app-data isn't available at this point.
valid_from: None,
};
let onchain_order_placement_event = OnchainOrderPlacement {
order_uid: ByteArray(order_uid.0),
Expand Down Expand Up @@ -680,18 +683,53 @@ fn extract_order_data_from_onchain_order_placement_event(
Ok((order_data, owner, signing_scheme, order_uid))
}

async fn insert_order_hooks(
/// Populates all app-data-derived order fields before the orders are persisted:
/// backfills each order's `valid_from` and indexes its pre/post hook
/// interactions. Must run before the orders are inserted (it mutates them).
/// Orders whose app-data is unknown or unparseable are left unchanged.
async fn handle_app_data(
db: &mut PgConnection,
orders: &[Order],
orders: &mut [Order],
trampoline: &HooksTrampoline::Instance,
) -> Result<()> {
let mut interactions_to_insert = vec![];
for order in orders.iter_mut() {
let appdata_json = database::app_data::fetch(db, &order.app_data)
.await
.context("failed to fetch appdata")?;
let Some(appdata_json) = appdata_json else {
tracing::debug!(order = ?order.uid, "appdata for order is unknown");
continue;
};
let Ok(parsed) = app_data::parse(&appdata_json) else {
tracing::debug!(appdata = %String::from_utf8_lossy(&appdata_json), "could not parse appdata");
continue;
};

let execute_via_trampoline = |hooks: Vec<app_data::Hook>| {
store_hooks(db, order, &parsed, trampoline).await?;
order.valid_from = parsed.valid_from.map(i64::from);
}
Ok(())
}

async fn store_hooks(
db: &mut PgConnection,
order: &Order,
parsed: &ProtocolAppData,
trampoline: &HooksTrampoline::Instance,
) -> Result<()> {
if parsed.hooks.pre.is_empty() && parsed.hooks.post.is_empty() {
return Ok(());
}

let interactions_count = database::orders::next_free_interaction_indices(db, order.uid)
.await
.context("failed to fetch interaction count")?;

let execute_via_trampoline = |hooks: &[app_data::Hook]| {
trampoline
.execute(
hooks
.into_iter()
.iter()
.map(|hook| Hook {
target: hook.target,
callData: alloy::primitives::Bytes::from(hook.call_data.clone()),
Expand All @@ -703,52 +741,35 @@ async fn insert_order_hooks(
.to_vec()
};

for order in orders {
let appdata_json = database::app_data::fetch(db, &order.app_data)
.await
.context("failed to fetch appdata")?;
let Some(appdata_json) = appdata_json else {
tracing::debug!(order = ?order.uid, "appdata for order is unknown");
continue;
};
let Ok(parsed) = app_data::parse(&appdata_json) else {
tracing::debug!(appdata = %String::from_utf8_lossy(&appdata_json), "could not parse appdata");
continue;
};
if parsed.hooks.pre.is_empty() && parsed.hooks.post.is_empty() {
continue; // no additional interactions to index
}

let interactions_count = database::orders::next_free_interaction_indices(db, order.uid)
.await
.context("failed to fetch interaction count")?;

if !parsed.hooks.pre.is_empty() {
let interaction = database::orders::Interaction {
let mut interactions = vec![];
if !parsed.hooks.pre.is_empty() {
interactions.push((
order.uid,
database::orders::Interaction {
target: ByteArray(trampoline.address().0.0),
value: 0.into(),
data: execute_via_trampoline(parsed.hooks.pre),
data: execute_via_trampoline(&parsed.hooks.pre),
index: interactions_count.next_pre_interaction_index,
execution: database::orders::ExecutionTime::Pre,
};
interactions_to_insert.push((order.uid, interaction));
}

if !parsed.hooks.post.is_empty() {
let interaction = database::orders::Interaction {
},
));
}
if !parsed.hooks.post.is_empty() {
interactions.push((
order.uid,
database::orders::Interaction {
target: ByteArray(trampoline.address().0.0),
value: 0.into(),
data: execute_via_trampoline(parsed.hooks.post),
data: execute_via_trampoline(&parsed.hooks.post),
index: interactions_count.next_post_interaction_index,
execution: database::orders::ExecutionTime::Post,
};
interactions_to_insert.push((order.uid, interaction));
}
},
));
}

database::orders::insert_or_overwrite_interactions(db, &interactions_to_insert)
database::orders::insert_or_overwrite_interactions(db, &interactions)
.await
.context("could not insert interactions for orders")
.context("could not insert interactions for order")
}

#[derive(prometheus_metric_storage::MetricStorage, Clone, Debug)]
Expand Down Expand Up @@ -1025,6 +1046,7 @@ mod test {
sell_token_balance: sell_token_source_into(expected_order_data.sell_token_balance),
buy_token_balance: buy_token_destination_into(expected_order_data.buy_token_balance),
cancellation_timestamp: None,
valid_from: None,
};
assert_eq!(onchain_order_placement, expected_onchain_order_placement);
assert_eq!(order, expected_order);
Expand Down Expand Up @@ -1138,6 +1160,7 @@ mod test {
sell_token_balance: sell_token_source_into(expected_order_data.sell_token_balance),
buy_token_balance: buy_token_destination_into(expected_order_data.buy_token_balance),
cancellation_timestamp: None,
valid_from: None,
};
assert_eq!(onchain_order_placement, expected_onchain_order_placement);
assert_eq!(order, expected_order);
Expand Down
1 change: 1 addition & 0 deletions crates/autopilot/src/infra/persistence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ impl Persistence {
&mut tx,
&updated_order_uids,
after_timestamp,
started_at.timestamp(),
)
.map(|result| match result {
Ok(order) => full_order_into_model_order(order)
Expand Down
2 changes: 1 addition & 1 deletion crates/database/src/jit_orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use {

pub const SELECT: &str = r#"
o.uid, o.owner, o.creation_timestamp, o.sell_token, o.buy_token, o.sell_amount, o.buy_amount,
o.valid_to, o.app_data, o.fee_amount, o.kind, o.partially_fillable, o.signature,
o.valid_to, NULL AS valid_from, o.app_data, o.fee_amount, o.kind, o.partially_fillable, o.signature,
o.receiver, o.signing_scheme, '\x9008d19f58aabd9ed0d60971565aa8510560ab41'::bytea AS settlement_contract, o.sell_token_balance, o.buy_token_balance,
'liquidity'::OrderClass AS class,
(SELECT COALESCE(SUM(t.buy_amount), 0) FROM trades t WHERE t.order_uid = o.uid) AS sum_buy,
Expand Down
Loading
Loading