Skip to content
Open
2 changes: 1 addition & 1 deletion crates/autopilot/src/database/auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,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 @@ -602,6 +602,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