feat(api): log the pool's non-swap events, to learn whether it logs orders
ci / gate (push) Successful in 4m21s
deploy / validate (push) Skipped
deploy / build (push) Successful in 9m9s
deploy / deploy-web (push) Successful in 10s
deploy / deploy-api (push) Successful in 26s

#41 asks whether `dcl.ref` logs limit-order events — which would say who
posts and withdraws each bid, where the book alone only shows that it
changed. The contract's source is not public where it was looked for, so
the chain is asked instead: `refdcl::fetch` already reads every direct
call in full, and now logs the first sighting of each non-swap `dcl.ref`
event per process with a sample of its data.

Refs #41

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015pkwBsR54NRmZyU4QVhvfj
This commit is contained in:
2026-10-06 19:49:13 +03:00
co-authored by Claude Opus 5.5
parent 6988368d6e
commit 025116fd2d
2 changed files with 55 additions and 0 deletions
+19
View File
@@ -196,6 +196,7 @@ async fn fetch_one(
let mut out = Vec::new();
// A failed receipt still reports its logs; only a successful one swapped.
for o in pool_outcomes.into_iter().filter(|o| o.succeeded) {
note_other_events(tx_hash, &o.logs);
for (i, s) in dcl::dcl_swaps(&o.logs)
.into_iter()
.filter(|s| holds_asset(&s.pool_id, asset_contract))
@@ -391,6 +392,24 @@ async fn record_history(
}
}
/// Log the first sighting of each non-swap `dcl.ref` event this process sees,
/// with a sample of its data: whether the pool logs limit orders, and in what
/// shape, is found out from the chain rather than assumed (blackbeard/observer#41).
fn note_other_events(tx_hash: &str, logs: &[String]) {
static SEEN: std::sync::Mutex<BTreeSet<String>> = std::sync::Mutex::new(BTreeSet::new());
for (name, data) in dcl::dcl_other_events(logs) {
let first = SEEN
.lock()
.unwrap_or_else(|p| p.into_inner())
.insert(name.clone());
if first {
let mut sample = data.to_string();
sample.truncate(600);
tracing::info!(event = %name, tx = %tx_hash, %sample, "dcl.ref event other than swap");
}
}
}
fn num(v: &Value, k: &str) -> u128 {
v.get(k)
.and_then(Value::as_str)
+36
View File
@@ -309,6 +309,29 @@ pub struct DclSwap {
pub protocol_fee: u128,
}
/// Every `dcl.ref` event in the logs other than `swap`, as `(name, data)`.
///
/// Whether the contract logs limit-order events — and so whether who posts and
/// withdraws a bid can be known, rather than inferred from the book — has not
/// been established from its source (blackbeard/observer#41). The fetch logs
/// what this returns, so the answer comes from the chain.
pub fn dcl_other_events(logs: &[String]) -> Vec<(String, Value)> {
logs.iter()
.filter_map(|line| line.strip_prefix(EVENT_PREFIX))
.filter_map(|j| serde_json::from_str::<Value>(j).ok())
.filter(|e| e.get("standard").and_then(Value::as_str) == Some("dcl.ref"))
.filter_map(|e| {
let name = e.get("event").and_then(Value::as_str)?;
(name != "swap").then(|| {
(
name.to_owned(),
e.get("data").cloned().unwrap_or(Value::Null),
)
})
})
.collect()
}
/// Every `dcl.ref` `swap` in one receipt outcome's logs.
///
/// The caller must already know the outcome succeeded and was executed by the
@@ -547,6 +570,19 @@ mod tests {
);
}
#[test]
fn non_swap_dcl_events_are_listed_and_swaps_are_not() {
let logs = vec![
r#"EVENT_JSON:{"standard":"dcl.ref","version":"1.0.0","event":"swap","data":[]}"#.to_owned(),
r#"EVENT_JSON:{"standard":"dcl.ref","version":"1.0.0","event":"order_added","data":[{"owner_id":"a.near"}]}"#.to_owned(),
r#"EVENT_JSON:{"standard":"nep141","event":"ft_transfer","data":[]}"#.to_owned(),
"plain text".to_owned(),
];
let found = dcl_other_events(&logs);
assert_eq!(found.len(), 1);
assert_eq!(found[0].0, "order_added");
}
#[test]
fn a_bid_order_absorbs_its_usdc_at_its_own_point() {
// The USDC/QTC pool's bid book, 2026-10-06 ~17:00 EEST, and the QTC