Skip to content

twap-monitor: index ComposableCoW v2 ConditionalOrderRemoved#472

Open
mfw78 wants to merge 1 commit into
feat/m4-retire-cow-conefrom
feat/m4-conditional-order-removed
Open

twap-monitor: index ComposableCoW v2 ConditionalOrderRemoved#472
mfw78 wants to merge 1 commit into
feat/m4-retire-cow-conefrom
feat/m4-conditional-order-removed

Conversation

@mfw78

@mfw78 mfw78 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

What

Indexes the ComposableCoW v2 ConditionalOrderRemoved event in twap-monitor and drops the corresponding watch (with its gates) when the removal provably postdates the watch's indexed create. Watch rows now carry a chain-position stamp (block, log-index) alongside the ABI-encoded params; created/removed topic-0s are pinned in wit/shepherd-cow/cow-events.wit and parity-tested against module.toml.

Why

The two subscription streams (create, remove) merge in arrival order, not chain order, so an unordered removal could otherwise drop a re-registered watch or apply a stale remove ahead of its create. Stamping the indexed position makes the merge order irrelevant: a removal lands only when it is provably later than the watch's create.

Closes #54

Testing

nextest: strategy.rs indexer/poll suite, incl. new cases - stale removal after re-register is ignored, later removal in its own dispatch drops the watch + gates while sparing siblings, redelivered older create keeps the later stamp, and a removal without a mined position is a no-op.

AI Assistance

Implemented with Claude Code.

Subscribe the twap-monitor to the ComposableCoW v2
ConditionalOrderRemoved topic-0 and pin it in the
shepherd:cow/cow-events package of record. The created and removed
subscription streams merge in arrival order, not chain order, so each
watch row carries the create log's (block, log-index) stamp and a
removal drops the watch (with its gates) only when it postdates the
stamp: a stale removal for a re-registered order is ignored, and an
unprovable ordering keeps the watch for the poll path's self-healing
drop.

@lgahdl lgahdl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified thoroughly, including actually building and running the test suite against this commit and cross-checking ConditionalOrderRemoved's topic-0 against upstream cow-rs's own keccak256 self-test — both match. The chain-position comparison is correct (derived Ord on {block, index} gives block-first lexicographic ordering, and < is the right comparison since a create and its own removal can never share a log index). All four named test cases genuinely test what their names claim: the stale-removal-after-re-register case creates then removes at an older position and asserts the watch survives; the drop-and-spare case seeds a sibling watch and confirms it's untouched while the target's gates are gone; the redelivered-older-create case confirms prior.max(indexed_at) isn't regressed; and the no-mined-position case uses the SDK's real pending-log representation (block_number/log_index both None) and confirms no panic. The row codec (versioned tag + two LE u64s ahead of the ABI payload) is a clean, minimally-coupled encoding with its own round-trip and malformed-input tests.

One minor test-coverage nit, not a correctness defect: no test covers same-block, different-log-index ordering (e.g. create at (7,5), a genuine removal at (7,6)) — worth adding alongside the existing cross-block cases, but the underlying comparison logic is already verified correct by inspection. Approving.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants