Skip to content

feat(shepherd-sdk): extract shared helpers from M2 modules (BLEU-840)#13

Open
brunota20 wants to merge 1 commit into
feat/shepherd-sdk-skeleton-bleu-835from
feat/shepherd-sdk-helpers-bleu-840
Open

feat(shepherd-sdk): extract shared helpers from M2 modules (BLEU-840)#13
brunota20 wants to merge 1 commit into
feat/shepherd-sdk-skeleton-bleu-835from
feat/shepherd-sdk-helpers-bleu-840

Conversation

@brunota20

Copy link
Copy Markdown
Collaborator

Summary

Lifts the helpers currently duplicated between `twap-monitor` and `ethflow-watcher` into `shepherd-sdk`. BLEU-843 will collapse the duplication in the modules; this PR only adds the SDK surface + tests.

Layout

```
crates/shepherd-sdk/src/
├── cow/
│ ├── order.rs gpv2_to_order_data
│ ├── composable.rs sol! IConditionalOrder + PollOutcome + decode_revert
│ └── error.rs RetryAction + classify_api_error + try_decode_api_error
└── chain/
└── eth_call.rs eth_call_params + parse_eth_call_result + decode_revert_hex
```

Design notes

  • Every helper takes primitive args (`&[u8]`, `&str`, `Option<&str>`) — the SDK stays world-neutral; modules unpack their wit-bindgen `HostError` / `Log` on the way in.
  • `PollOutcome::Ready` boxes `GPv2OrderData` (~300 B) to keep the enum cache-friendly.
  • `RetryAction::Backoff { seconds }` is parked (`#[allow(dead_code)]`) — cowprotocol's `retry_hint()` is bool-only today.
  • `classify_api_error(None) → TryNextBlock` is the safe default — a flaky orderbook should not be treated as a permanent rejection.

Stacks on #12 (BLEU-835 skeleton).

Linear: BLEU-840.

Test plan

  • `cargo test -p shepherd-sdk` — 27 host tests (1 prelude + 6 gpv2 marker mapping + 7 revert decode + 6 retry classification + 5 eth-call plumbing + 2 misc).
  • `cargo check --target wasm32-wasip2 -p shepherd-sdk`.
  • `cargo clippy -p shepherd-sdk --tests -- -Dwarnings` + `--target wasm32-wasip2` clean.

Lifts the helpers currently duplicated between twap-monitor and
ethflow-watcher into shepherd-sdk so BLEU-843 can collapse the
duplication, and so future strategy modules consume them straight
from the SDK.

Layout:

  crates/shepherd-sdk/src/
  ├── cow/
  │   ├── order.rs        gpv2_to_order_data
  │   ├── composable.rs   sol! IConditionalOrder + PollOutcome
  │   │                   + decode_revert
  │   └── error.rs        RetryAction + classify_api_error
  │                       + try_decode_api_error
  └── chain/
      └── eth_call.rs     eth_call_params
                          + parse_eth_call_result
                          + decode_revert_hex

Every helper takes primitive arguments (`&[u8]`, `&str`,
`Option<&str>`, slices) so the SDK stays world-neutral — modules
unpack their wit-bindgen `HostError` / `Log` into primitives on
the way in. That keeps the SDK testable without a wasm toolchain
and re-usable across worlds (M3 examples, future strategies).

Notable shape:

- `cow::composable::PollOutcome::Ready` boxes `GPv2OrderData`
  (~300 B) so the enum stays cache-friendly when the lifecycle
  handler in BLEU-830 routes outcomes around.
- `cow::error::RetryAction::Backoff { seconds }` is parked
  (`#[allow(dead_code)]`) for the future server-supplied hint;
  cowprotocol's `retry_hint()` is bool-only today.
- `cow::error::classify_api_error(None) -> TryNextBlock` is the
  safe default — a flaky orderbook should not be treated as a
  permanent rejection.

Tests: 26 host tests covering every helper (6 gpv2 marker
mapping, 7 revert decode, 6 retry classification, 5 eth-call
plumbing, 1 SolError selector). Clippy clean on host and
wasm32-wasip2.

The modules in `modules/twap-monitor` and `modules/ethflow-
watcher` still carry their own copies; BLEU-843 deletes them.
@linear-code

linear-code Bot commented Jun 17, 2026

Copy link
Copy Markdown

BLEU-840

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.

1 participant