Skip to content

intent: CoW venue adapter and flagship module ports #138

Description

@mfw78

Problem. Doc 09 step 3b (PR #132): CoW must become the first venue adapter, and the flagship modules must prove the pool. The nullisLabs composable-cow fork makes the poll path structured and non-reverting, so the off-chain side becomes a generic ComposableCoW poller with no handler-specific logic.

Scope. The cow-venue module as a distinct venue speaker built on three WIT layers: the CoW venue wit (shepherd:cow), the venue-agnostic intent wit (nexum:intent, nexum:value-flow, nexum:adapter), and the runtime host wit (nexum:host). Three feature slices: default (body types + borsh codec); client (typed client + orderbook submit-error classification for modules); adapter (the nexum:adapter component). The poll reads the structured PollResult (generator/fill/filledAmount/restriction) from the contract's non-reverting poll(); the revert-decode lives on-chain in BaseConditionalOrder.poll(), so the module does no selector decode. The verdict is GeneratorResultCode + bytes4 reasonCode (log only); scheduling comes from nextPollTimestamp/waitUntil. Golden vectors published per the venue-is-a-spec rule. twap-monitor generalises into a handler-agnostic ccow-monitor (TWAP survives as watch scope + vectors, not code); ethflow keeps its observe path. The legacy cow cone retires: wit/shepherd-cow, shepherd-cow-host, shepherd-sdk/src/cow.

Two classification concerns, kept separate. (a) The ComposableCoW POLL verdict comes from the contract (GeneratorResultCode + bytes4 reasonCode); there is no off-chain table and no string reasons. (b) The CoW ORDERBOOK-API submit-error errorType-to-action table (#236) stays as data: it classifies the REST POST /api/v1/orders response, orthogonal to the poll. #236 owns (b) and folds #75/#48/#121 once; it does not own poll decode.

Drive any handler (new scope, the substance of the generic monitor). (i) IOrderModule sandbox for NEEDS_INPUT offchainInput acquisition (content-hash-gated, output distrusted); (ii) IOrderManifest enumeration + offchainInput = abi.encode(uint256 index) fan-out for multi-order-per-poll; (iii) merkle-payload discovery (fetch mirror, recompute root, reconstruct proofs). None is needed for the five flagship handlers (none emits PollNeedsOffchainInput), so all three are follow-on.

Dependencies. Intent core (#137), keeper (#135), and #133 (appData hash-only lands first so the adapter never grows the redundant GET).

Notes. appData travels as the 32-byte on-chain hash; the flagship venue surface is submit + status only. Rename set from the fork: getTradeableOrder to generateOrder; PollTryAtEpoch(uint,string) to PollTryAtTimestamp(uint,bytes4); PollNever removed (use OrderNotValid); getTradeableOrderWithSignature returns PollResult, not (order,bytes); poll no longer reverts. Pool accepted(receipt) is post-submit, so the pre-submit idempotency guard is preserved only if the order UID stays a cow-venue guest concern feeding the SDK journal.


Next-train plan (stage only)

Current state. The legacy CoW surface is the pre-adapter path on the OLD upstream reverting poll (shepherd-cow-host + shepherd-sdk/src/cow/*). The fork's structured-poll registry is 2.0.0-dev, deployed on no chain, so the poll wire cannot retarget yet. This train stages the dependency-light body and table work.

Children this train:

Migration waves (HYBRID; the poll retarget is gated on fork deploy):

  • W1 (now, Rust-only): rework feat(sdk): add keeper conditional-source seam and CoW run loop #239's ConditionalSource::Outcome to a Verdict mirroring GeneratorResultCode + hints; land refactor(twap-monitor): port poll loop onto keeper #240's twap poll behind a named LegacyRevertAdapter (maps the 5 deployed-1.x selectors to Verdict). twap posts on testnet through the target seam. Grant M2 met.
  • W2 (gated on fork deployments/networks.json non-empty on a shepherd chain, off the grant clock): replace the adapter with a direct checkOrder/getTradeableOrderWithSignature to PollResult struct-read; delete shepherd-sdk/src/cow/composable.rs and the twap poll body (poll_one/decode_return/classify_poll_error, TryAtEpoch/TryOnBlock); regenerate golden vectors against bytes4 reasonCode + PollResult.
  • W3 (intent: CoW venue adapter and flagship module ports #138 follow-ons): IOrderModule, IOrderManifest fan-out, merkle discovery.

Deferred to follow-on train (Waves G to J): cow adapter component + timeout middleware (resolves #41) + requires-signing submit; golden vectors + conformance kit wiring; [[adapters]] bundling; re-point twap and ethflow onto the pool; retire the legacy cow cone (wit/shepherd-cow, shepherd-cow-host, shepherd-sdk/src/cow); #138 owns this deletion, #136's workspace-member removal sequences after it.

Merge gate: the poll retarget (shepherd-sdk/src/cow/composable.rs, twap-monitor/src/strategy.rs, ADR-0006) must not merge until the fork's deployments/networks.json is non-empty on a shepherd target chain.

Blocked by: #137, #135, #133.

Metadata

Metadata

Assignees

No one assigned

    Labels

    component/cow-integrationshepherd:cow / cow-api order submissionepicTracks a larger initiative.pr-trainPart of the current stacked PR train; lands in sequence, do not merge out of order.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions