Skip to content

feat(ethflow-watcher): build OrderCreation + submit + apply retry_hint (BLEU-833)#10

Open
brunota20 wants to merge 3 commits into
feat/ethflow-watcher-decode-bleu-832from
feat/ethflow-watcher-submit-bleu-833
Open

feat(ethflow-watcher): build OrderCreation + submit + apply retry_hint (BLEU-833)#10
brunota20 wants to merge 3 commits into
feat/ethflow-watcher-decode-bleu-832from
feat/ethflow-watcher-submit-bleu-833

Conversation

@brunota20

Copy link
Copy Markdown
Collaborator

Summary

`on_event(Event::Logs)` now ends in a complete pipeline:

  1. `decode_order_placement` (BLEU-832) lifts the log to `DecodedPlacement` (contract, sender, order, onchain signature, refund data).
  2. `build_eth_flow_creation` translates to typed `(OrderCreation, OrderUid)`:
    • `gpv2_to_order_data` maps the on-chain `bytes32` markers to `OrderKind` / balance enums.
    • `to_signature` lifts `OnchainSignature` to `Signature::Eip1271(bytes)` or `Signature::PreSign`. The hidden `__Invalid` sol! variant becomes `None` (placement skipped).
    • `OrderData::uid(domain, contract)` computes the canonical 56-byte UID; a Warn fires on drift against the orderbook's reply.
    • `from` = EthFlow contract (the EIP-1271 verifier), not the user's `sender`.
    • `app_data` is fixed to `EMPTY_APP_DATA_JSON` — placements pinning a real IPFS document are rejected and skipped.
  3. `cow_api::submit_order(chain_id, body)`.
  4. Persist outcome:
    • success → `submitted:{uid}`
    • retriable → `backoff:{uid}` (same `OrderPostError` classification as BLEU-829)
    • permanent → `dropped:{uid}`

`apply_submit_retry` mirrors BLEU-829's `classify_submit_error`. When the host forwards the orderbook JSON via `host-error.data`, the dispatch is data-driven; absent data, the safe default is `backoff:` rather than `dropped:`.

The `RetryAction::Backoff { seconds }` variant is parked (cowprotocol's surface today is bool-only).

Stacks on #9 (BLEU-832 decode).

Linear: BLEU-833. Ref ADR-0006.

Test plan

  • `cargo test -p ethflow-watcher` — 10 host tests (2 BLEU-832 decode regressions + 5 BLEU-833 order-build edges + 3 error-classification arms).
  • `cargo clippy --target wasm32-wasip2 -p ethflow-watcher -- -Dwarnings`.
  • `cargo clippy -p ethflow-watcher --tests -- -Dwarnings`.
  • `cargo build --target wasm32-wasip2 --release -p ethflow-watcher` — 268 KB .wasm (was 96 KB after BLEU-832; OrderCreation + serde_json + DomainSeparator + OrderUid surface linked in).
  • End-to-end against a Sepolia ETH-flow deployment — pending BLEU-834 module.toml + host `host-error.data` forwarding.

…(BLEU-833)

\`on_event(Event::Logs)\` now ends in a complete pipeline:

1. \`decode_order_placement\` (BLEU-832) lifts the log to a
   \`DecodedPlacement\` carrying the contract, sender, order,
   onchain signature and refund pointer.
2. \`build_eth_flow_creation\` translates that into a typed
   \`(OrderCreation, OrderUid)\`:
   - \`gpv2_to_order_data\` maps the on-chain \`bytes32\` markers
     to the typed \`OrderKind\` / balance enums; same logic as
     the TWAP module, kept inline because the two crates are
     independent.
   - \`to_signature\` lifts \`OnchainSignature\` into
     \`Signature::Eip1271(bytes)\` or \`Signature::PreSign\`.
     The hidden \`__Invalid\` sol! variant is surfaced as
     \`Option::None\` so a malformed event skips the placement
     instead of panicking.
   - \`OrderData::uid(domain, contract)\` computes the canonical
     56-byte order UID locally; the orderbook returns the same
     value from POST /api/v1/orders and a Warn fires if they
     drift (domain or owner divergence).
   - \`from\` = EthFlow contract (the EIP-1271 verifier), NOT
     the user's \`sender\` — matches the on-chain signing scheme.
   - \`app_data\` is fixed to \`EMPTY_APP_DATA_JSON\` for now;
     placements pinning a real IPFS document are rejected by
     \`from_signed_order_data\` (digest mismatch) and skipped.
3. Serialise + \`cow_api::submit_order(chain_id, body)\`.
4. Persist the outcome:
   - success    -> \`submitted:{uid}\`
   - retriable  -> \`backoff:{uid}\`   (same OrderPostError
                                       classification path as
                                       BLEU-829)
   - permanent  -> \`dropped:{uid}\`

\`apply_submit_retry\` mirrors BLEU-829's
\`classify_submit_error\` — when the host forwards the orderbook
JSON via \`host-error.data\`, the dispatch is data-driven;
absent data, the safe default is \`backoff:\` (retry next event)
rather than \`dropped:\`.

The \`Backoff { seconds }\` variant of \`RetryAction\` is parked:
cowprotocol's surface today is bool-only, so until a server
hint shows up (Retry-After or a typed delay) the variant
remains intentionally producer-less.

Tests: 10 host tests covering BLEU-832 (2 decode regressions)
and BLEU-833 (5 order-build edges + 3 error-classification
arms). \`.wasm\` 268 KB (was 96 KB; the OrderCreation +
serde_json + DomainSeparator + OrderUid surface get linked
in). Same scope-knot on app-data resolution as the TWAP
module; same host follow-up on \`host-error.data\` forwarding.

Linear: BLEU-833. Ref ADR-0006.
@linear-code

linear-code Bot commented Jun 15, 2026

Copy link
Copy Markdown

BLEU-833

\`submit_placement\` now checks for a prior terminal marker before
calling \`cow_api::submit_order\`. Re-delivered \`OrderPlacement\`
logs (engine restart with replay, host reconnect, indexer
back-fill) would otherwise re-submit the same body, the orderbook
would reject \`DuplicateOrder\` (permanent), and the module would
end up with BOTH \`submitted:{uid}\` AND \`dropped:{uid}\` written
for the same key.

The guard is a typed `prior_outcome(uid_hex)` lookup:
- \`Submitted\` -> skip (the most common re-delivery cause)
- \`Dropped\`   -> skip (orderbook permanently rejected previously)
- \`Backoff\`   -> proceed: a transient failure deserves a fresh
                  attempt on re-delivery; the new outcome
                  overrides.
- \`None\`      -> proceed: a clean first try.

On a successful submit, any previous \`backoff:\` marker is also
cleared so the local store carries at most one outcome flag per
UID at rest. Same cleanup happens on a permanent drop in
\`apply_submit_retry\`.

Linear: BLEU-833 (fix on the same PR — review identified the
re-delivery gap).
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