Skip to content
Open
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
58 changes: 58 additions & 0 deletions modules/twap-monitor/src/keeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,64 @@ mod tests {
});
}

#[test]
fn removal_before_its_create_self_heals_via_the_first_poll() {
// The exact race module.toml's own comment warns about: the two
// log streams merge in arrival order, not chain order, so a
// removal can reach `on_chain_logs` before the create it
// cancels. `removal_of_an_unindexed_watch_is_a_no_op` already
// confirms the removal alone is silently dropped in that case -
// this chains the rest of the story: the create that follows
// persists the watch anyway, with no memory of the earlier
// removal, and the very first poll must still tear it down.
//
// The revert used here is `SingleOrderNotAuthed()` - the actual
// selector the deployed `ComposableCow._auth` reverts with for a
// removed order (nullislabs/composable-cow/src/ComposableCow.sol),
// not one of the five legacy `IConditionalOrder` reasons
// `poll_invalid_drops_watch_and_gates` already covers.
// `LegacyRevertAdapter::classify`'s unrecognised-selector
// fallback is what has to catch this one.
let host = MockHost::new();
let venue = MockVenue::default();
let owner = address!("0011223344556677889900AABBCCDDEEFF001122");
let params = sample_params();
let hash = keccak256(params.abi_encode());
let key = watch_key(&owner, &hash);

on_chain_logs(&host, &[make_removed_log(owner, hash, at(2, 0))]).unwrap();
assert_eq!(
host.store.len(),
0,
"removal of an unindexed watch is a no-op"
);

on_chain_logs(&host, &[make_log(owner, &params, at(1, 0))]).unwrap();
assert!(
host.store.snapshot().contains_key(&key),
"the create persists the watch with no memory of the earlier removal",
);

let selector = alloy_primitives::keccak256(b"SingleOrderNotAuthed()")[..4].to_vec();
host.chain.respond_to(
"eth_call",
programmed_eth_call_params(owner, &params),
Err(ChainError::Rpc(nexum_sdk::host::RpcError {
code: 3,
message: "execution reverted".into(),
data: Some(selector.into()),
})),
);

dispatch(&host, &venue, sample_block(1_000)).unwrap();

assert!(
!host.store.snapshot().contains_key(&key),
"the first poll against a chain-dead order must self-heal the stale watch",
);
assert_eq!(venue.submit_count(), 0, "a dead order is never submitted");
}

/// The supervisor builds log filters from this manifest's chain-log
/// `event_signature` pins, so a drift from a decoder topic-0
/// subscribes to one topic and decodes another. Compares the two
Expand Down