feat(composable): bindings for M2 contract mods (draft, depends on composable-cow PRs) - #7
Draft
brunota20 wants to merge 1 commit into
Draft
feat(composable): bindings for M2 contract mods (draft, depends on composable-cow PRs)#7brunota20 wants to merge 1 commit into
brunota20 wants to merge 1 commit into
Conversation
7 tasks
brunota20
force-pushed
the
feat/composable-cow-m2-bindings
branch
from
June 24, 2026 18:49
281528e to
d9c4772
Compare
brunota20
added a commit
to bleu/nullis-shepherd
that referenced
this pull request
Jun 24, 2026
Integration branch for the four contract surfaces proposed in: - brunota20/composable-cow#1 (TWAP polling hints) - brunota20/composable-cow#2 (ConditionalOrderRegistered event) - brunota20/composable-cow#3 (batchGetTradeableOrdersWithSignature) - brunota20/composable-cow#4 (getOrderInfo) Consumes the new bindings from bleu/cow-rs#7 (feat/composable-cow-m2-bindings) via a `[patch.crates-io]` rev bump from `57f5f55` -> `281528e`. Changes: - twap-monitor's per-block poll loop carries a new batched code path (`poll_all_watches_batched`) that issues one batched eth_call (`ComposableCoW.batchGetTradeableOrdersWithSignature`) instead of N per-watch calls. Gated behind a runtime flag (`module.toml::[config].use_batch_poll`, default `"false"`); legacy per-watch path stays the only runtime code path until the M2 contracts deploy, so shepherd keeps working against today's ComposableCoW. - The batched path bridges `cowprotocol::PollOutcome` (M2 binding shape) to the existing `shepherd_sdk::cow::PollOutcome` lifecycle, so TWAP's new precise `PollTryAtEpoch(t0/nextPartStart, ...)` and `PollNever("all parts settled")` reverts flow through the same `outcome_to_update` -> gate-write dispatch the legacy path uses. - `ComposableCoWError` (`SingleOrderNotAuthed`, `SwapGuardRestricted`, etc.) per-slot reverts drop the watch; `UnknownRevert` is logged at Warn and left in place for triage. - Length-mismatch defence: if the batched response slot count diverges from the request count, the whole block is deferred (no per-watch state changes) and a Warn fires. - Seven new MockHost tests cover the batched path: Ready submit, `PollTryAtEpoch` -> `next_epoch:` gate, `PollNever` -> drop, `SingleOrderNotAuthed` -> drop, length-mismatch defer, runtime-flag dispatch routing, and `ConditionalOrderRegistered` indexed-handler decode (pins the binding shape for the eventual subscription patch). - `docs/operations/composable-cow-m2-integration.md` captures the staged rollout plan, the cleanups that follow Stage 3 (notably the COW-1077 `_twap_calldata.py` workaround), and the risks. Draft: contracts not deployed yet. This branch lands the integration code so shepherd ships ready-to-flip when the M2 contract mods merge upstream. AI Assistance: Claude Code (Opus 4.7) wrote the integration code against the new cow-rs bindings. A human (Bruno) is accountable.
brunota20
added a commit
to bleu/nullis-shepherd
that referenced
this pull request
Jun 25, 2026
Integration branch for the four contract surfaces proposed in: - brunota20/composable-cow#1 (TWAP polling hints) - brunota20/composable-cow#2 (ConditionalOrderRegistered event) - brunota20/composable-cow#3 (batchGetTradeableOrdersWithSignature) - brunota20/composable-cow#4 (getOrderInfo) Consumes the new bindings from bleu/cow-rs#7 (feat/composable-cow-m2-bindings) via a `[patch.crates-io]` rev bump from `57f5f55` -> `281528e`. Changes: - twap-monitor's per-block poll loop carries a new batched code path (`poll_all_watches_batched`) that issues one batched eth_call (`ComposableCoW.batchGetTradeableOrdersWithSignature`) instead of N per-watch calls. Gated behind a runtime flag (`module.toml::[config].use_batch_poll`, default `"false"`); legacy per-watch path stays the only runtime code path until the M2 contracts deploy, so shepherd keeps working against today's ComposableCoW. - The batched path bridges `cowprotocol::PollOutcome` (M2 binding shape) to the existing `shepherd_sdk::cow::PollOutcome` lifecycle, so TWAP's new precise `PollTryAtEpoch(t0/nextPartStart, ...)` and `PollNever("all parts settled")` reverts flow through the same `outcome_to_update` -> gate-write dispatch the legacy path uses. - `ComposableCoWError` (`SingleOrderNotAuthed`, `SwapGuardRestricted`, etc.) per-slot reverts drop the watch; `UnknownRevert` is logged at Warn and left in place for triage. - Length-mismatch defence: if the batched response slot count diverges from the request count, the whole block is deferred (no per-watch state changes) and a Warn fires. - Seven new MockHost tests cover the batched path: Ready submit, `PollTryAtEpoch` -> `next_epoch:` gate, `PollNever` -> drop, `SingleOrderNotAuthed` -> drop, length-mismatch defer, runtime-flag dispatch routing, and `ConditionalOrderRegistered` indexed-handler decode (pins the binding shape for the eventual subscription patch). - `docs/operations/composable-cow-m2-integration.md` captures the staged rollout plan, the cleanups that follow Stage 3 (notably the COW-1077 `_twap_calldata.py` workaround), and the risks. Draft: contracts not deployed yet. This branch lands the integration code so shepherd ships ready-to-flip when the M2 contract mods merge upstream. AI Assistance: Claude Code (Opus 4.7) wrote the integration code against the new cow-rs bindings. A human (Bruno) is accountable.
Adds Rust bindings + helpers for four contract changes from the M2 grant deliverable (smart-contract modifications to ComposableCoW + TWAP handler): - ConditionalOrderRegistered (additive event, indexed handler + ctx). ABI bindings + topic filter helper. - batchGetTradeableOrdersWithSignature view function + BatchOrderRequest / BatchOrderResult struct bindings + decoder helpers that lower per-request revert payloads into the existing PollOutcome / ComposableCoWError taxonomy. - getOrderInfo combined accessor + OrderInfo struct binding. - Decoder extended to ensure TWAP's new precise poll reverts (PollTryAtEpoch / PollNever) are recognised by the IConditionalOrder revert taxonomy. Tests cover ABI round-trip, topic-0 hashes against canonical keccak, the batch decoder over success / poll-hint / composable error / unknown-revert paths, and selector locks for the new function calls.
brunota20
added a commit
to bleu/nullis-shepherd
that referenced
this pull request
Jun 25, 2026
Integration branch for the four contract surfaces proposed in: - brunota20/composable-cow#1 (TWAP polling hints) - brunota20/composable-cow#2 (ConditionalOrderRegistered event) - brunota20/composable-cow#3 (batchGetTradeableOrdersWithSignature) - brunota20/composable-cow#4 (getOrderInfo) Consumes the new bindings from bleu/cow-rs#7 (feat/composable-cow-m2-bindings) via a `[patch.crates-io]` rev bump from `57f5f55` -> `281528e`. Changes: - twap-monitor's per-block poll loop carries a new batched code path (`poll_all_watches_batched`) that issues one batched eth_call (`ComposableCoW.batchGetTradeableOrdersWithSignature`) instead of N per-watch calls. Gated behind a runtime flag (`module.toml::[config].use_batch_poll`, default `"false"`); legacy per-watch path stays the only runtime code path until the M2 contracts deploy, so shepherd keeps working against today's ComposableCoW. - The batched path bridges `cowprotocol::PollOutcome` (M2 binding shape) to the existing `shepherd_sdk::cow::PollOutcome` lifecycle, so TWAP's new precise `PollTryAtEpoch(t0/nextPartStart, ...)` and `PollNever("all parts settled")` reverts flow through the same `outcome_to_update` -> gate-write dispatch the legacy path uses. - `ComposableCoWError` (`SingleOrderNotAuthed`, `SwapGuardRestricted`, etc.) per-slot reverts drop the watch; `UnknownRevert` is logged at Warn and left in place for triage. - Length-mismatch defence: if the batched response slot count diverges from the request count, the whole block is deferred (no per-watch state changes) and a Warn fires. - Seven new MockHost tests cover the batched path: Ready submit, `PollTryAtEpoch` -> `next_epoch:` gate, `PollNever` -> drop, `SingleOrderNotAuthed` -> drop, length-mismatch defer, runtime-flag dispatch routing, and `ConditionalOrderRegistered` indexed-handler decode (pins the binding shape for the eventual subscription patch). - `docs/operations/composable-cow-m2-integration.md` captures the staged rollout plan, the cleanups that follow Stage 3 (notably the COW-1077 `_twap_calldata.py` workaround), and the risks. Draft: contracts not deployed yet. This branch lands the integration code so shepherd ships ready-to-flip when the M2 contract mods merge upstream.
brunota20
force-pushed
the
feat/composable-cow-m2-bindings
branch
from
June 25, 2026 17:48
d9c4772 to
3ba2075
Compare
brunota20
added a commit
to bleu/nullis-shepherd
that referenced
this pull request
Jun 26, 2026
Integration branch for the four contract surfaces proposed in: - brunota20/composable-cow#1 (TWAP polling hints) - brunota20/composable-cow#2 (ConditionalOrderRegistered event) - brunota20/composable-cow#3 (batchGetTradeableOrdersWithSignature) - brunota20/composable-cow#4 (getOrderInfo) Consumes the new bindings from bleu/cow-rs#7 (feat/composable-cow-m2-bindings) via a `[patch.crates-io]` rev bump from `57f5f55` -> `281528e`. Changes: - twap-monitor's per-block poll loop carries a new batched code path (`poll_all_watches_batched`) that issues one batched eth_call (`ComposableCoW.batchGetTradeableOrdersWithSignature`) instead of N per-watch calls. Gated behind a runtime flag (`module.toml::[config].use_batch_poll`, default `"false"`); legacy per-watch path stays the only runtime code path until the M2 contracts deploy, so shepherd keeps working against today's ComposableCoW. - The batched path bridges `cowprotocol::PollOutcome` (M2 binding shape) to the existing `shepherd_sdk::cow::PollOutcome` lifecycle, so TWAP's new precise `PollTryAtEpoch(t0/nextPartStart, ...)` and `PollNever("all parts settled")` reverts flow through the same `outcome_to_update` -> gate-write dispatch the legacy path uses. - `ComposableCoWError` (`SingleOrderNotAuthed`, `SwapGuardRestricted`, etc.) per-slot reverts drop the watch; `UnknownRevert` is logged at Warn and left in place for triage. - Length-mismatch defence: if the batched response slot count diverges from the request count, the whole block is deferred (no per-watch state changes) and a Warn fires. - Seven new MockHost tests cover the batched path: Ready submit, `PollTryAtEpoch` -> `next_epoch:` gate, `PollNever` -> drop, `SingleOrderNotAuthed` -> drop, length-mismatch defer, runtime-flag dispatch routing, and `ConditionalOrderRegistered` indexed-handler decode (pins the binding shape for the eventual subscription patch). - `docs/operations/composable-cow-m2-integration.md` captures the staged rollout plan, the cleanups that follow Stage 3 (notably the COW-1077 `_twap_calldata.py` workaround), and the risks. Draft: contracts not deployed yet. This branch lands the integration code so shepherd ships ready-to-flip when the M2 contract mods merge upstream.
ribeirojose
added a commit
that referenced
this pull request
Jul 1, 2026
Three additive signing-ergonomics gaps, all sharing the same private machinery so they land as one coherent surface: - Give `OrderData` the recover counterpart it lacked: `recover_signer` and `recover_ecdsa` build the EIP-712 payload internally, so external consumers no longer need the doc-hidden `eip712::Order`. The orderbook's `verify_owner` now routes through `recover_signer` instead of reaching into that module (no behaviour change). (#7) - Make the forward digest derivation public: `signing_message` is now `pub` (and re-exported), with a thin `OrderData::signing_hash` wrapper. A new ungated wasm export `ethsign_digest(order_data, chain)` returns the exact EIP-191 `personal_sign` bytes for the EthSign inject-provider path, completing the "construct, sign externally, lift back" story for the one scheme that was missing it. (#9) - Add named, validating constructors for the on-chain schemes: `Signature::eip1271(bytes)` enforces the `EIP1271_MAX_LEN` cap that the bare variant skips, and `Signature::pre_sign()` builds the unit variant without slice gymnastics. (cowdao-grants#13) Closes #7 Closes #9 Closes cowdao-grants#13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Status: Draft. Depends on the four upstream
composable-cowproposal PRs landing first. Once those PRs merge intobleu/composable-cow(or upstreamcowprotocol/composable-cow), this PR's selectors / event signatures / struct field orders are locked against the canonical Solidity sources via the new tests; no further changes should be needed here.What this adds
Additive Rust bindings + pure helpers for the four contract changes proposed in the composable-cow grant work. Every addition matches the existing cow-rs pattern:
sol!-derived types + pure encode/decode helpers, noProviderplumbing — callers wrap their own RPC layer.1.
ConditionalOrderRegisteredeventAdded inside the existing
ComposableCoWsol! interface block. Indexedowner/handler/ctx(=H(params)) lets watch towers filter at the RPC level withtopics: [REGISTERED_HASH, null, handlerAddr]. The existingConditionalOrderCreatedtopic-0 is untouched (no indexer breakage).registered_topic_filter_by_handler(Address) -> [Option<B256>; 4]builds the four-slot filter array a caller passes toeth_subscribe logs.2.
batchGetTradeableOrdersWithSignatureBatchOrderRequestandBatchOrderResultstruct bindings + the function selector.BatchOrderResult.orderreferencescrate::contracts::GPv2OrderDatadirectly (sol!resolves the type across sibling blocks — confirmed by the existingOrderPlacementevent reusing the same type).decode_batch_order_result/decode_batch_order_resultslower each result into aBatchOrderOutcome:GPv2OrderDatais boxed insideSubmittedto keep the enum compact (the order struct alone is ~320 bytes; clippy'slarge_enum_variantwould otherwise fire, and the indirection is invisible to callers via auto-deref).3.
getOrderInfocombined accessorOrderInfostruct binding (hash,authorized,cabinetValue,swapGuard) + function selector. Mirrors the on-chain helper that bundles four storage reads into one round trip.4.
IConditionalOrdererror decoderThe five canonical errors from
IConditionalOrder.sol(OrderNotValid,PollTryNextBlock,PollTryAtBlock,PollTryAtEpoch,PollNever) bound in a new sibling sol! interface, plus adecode_conditional_order_revert(&[u8]) -> Option<PollOutcome>decoder.This is what unlocks TWAP's new behaviour from the polling-hints proposal:
PollTryAtEpoch(t0, "before first part"),PollTryAtEpoch(nextPartStart, "between parts"), andPollNever("all parts settled")all decode out of the box. Tests assert each of the five errors round-trips through the decoder, withtimestamp/blockNumber/reasonarguments preserved byte-exact.5.
ComposableCoW*NotAuthed-style errorsSix errors (
ProofNotAuthed,SingleOrderNotAuthed,SwapGuardRestricted,InvalidHandler,InvalidFallbackHandler,InterfaceNotSupported) bound in a siblingComposableCoWErrorsinterface +decode_composable_cow_error(&[u8]) -> Option<ComposableCoWError>decoder. Cascades behinddecode_conditional_order_revertinsidedecode_batch_order_result.Files
crates/cowprotocol-primitives/src/composable.rs— extended (events, structs, functions, decoders, helpers, tests)crates/cowprotocol-primitives/src/lib.rs— re-export additionscrates/cowprotocol/src/lib.rs— re-export additionsPublic surface added (all additive — no existing API changed)
Tests (16 new + 3 extended cases)
conditional_order_registered_round_trips— event topic encodingregistered_topic_filter_pins_handler_and_signature— filter helperbatch_order_request_round_trips,batch_order_result_round_trips— ABI round-tripsdecode_batch_order_result_success,_poll_try_at_epoch,_composable_cow_error,_unknown_revert— outcome cascadedecode_batch_order_results_preserves_order— order preservation across mixed batchorder_info_round_trips,get_order_info_call_round_trips— getOrderInfo combined accessordecode_conditional_order_revert_covers_all_five_errors— all 5IConditionalOrdererrors + the three TWAP reverts byte-exactdecode_conditional_order_revert_returns_none_for_unrelated_payloads— safetyconditional_order_error_selectors_match_keccak,composable_cow_error_selectors_match_keccak— selector locksdecode_composable_cow_error_covers_all_variantscomposable_cow_selectors_match_keccak(the two new view functions)composable_cow_event_topic_hashes_match_keccakGates
Test plan
composable-cowPR sources once the upstream PRs settle to confirm field names, argument order, and selector strings.batchGetTradeableOrdersWithSignaturereturning a mixed batch (one success, onePollTryAtEpoch, onePollNever) and confirm decoding lines up.ConditionalOrderRegisteredtopic filter delivers only the expected handler's events when subscribed viaeth_subscribe logson a live RPC.