Skip to content

Add Ophis skill: MEV-protected same-chain swaps (CoW Protocol)#563

Open
san-npm wants to merge 2 commits into
BankrBot:mainfrom
san-npm:add-ophis-skill
Open

Add Ophis skill: MEV-protected same-chain swaps (CoW Protocol)#563
san-npm wants to merge 2 commits into
BankrBot:mainfrom
san-npm:add-ophis-skill

Conversation

@san-npm

@san-npm san-npm commented Jul 13, 2026

Copy link
Copy Markdown

Ophis — MEV-protected same-chain swaps (CoW Protocol)

Adds the ophis skill: same-chain token swaps routed through Ophis, a CoW-Protocol intent-settlement layer. Instead of an AMM swap that can be sandwiched, the order settles in a batch auction — uniform clearing price, surplus (price improvement) returned to the trader, and gasless for the user (solvers pay the settlement gas; the wallet only authorizes).

Complements the existing bridging skills (symbiosis, trails) — this is same-chain best execution, not cross-chain.

How it executes from a Bankr wallet

CoW orders are off-chain signed intents, so this skill uses the presign scheme — the Bankr wallet only submits transactions, never signs a raw message:

quote → build Ophis appData → PUT /app_data/{hash} → approve the CoW VaultRelayer (via Bankr Submit) → POST /orders with signingScheme: "presign" (returns the order UID) → setPreSignature(uid, true) on the Settlement contract (via Bankr Submit) → solvers settle it in the next batch.

Chains

Base and Unichain are the strongest targets (Bankr-native and a live Ophis stack); also Arbitrum, Polygon, BNB, Ethereum, Optimism. Same-chain only.

Files

ophis/SKILL.md, ophis/catalog.json, ophis/scripts/{ophis_common,ophis-quote,ophis-swap}.py, ophis/references/{api,chains-and-tokens}.md. Requires python3, a keccak library (pysha3 / pycryptodome / eth-hash), and BANKR_API_KEY.

Notes for reviewers

  • Endpoints, contract addresses, and the appData partner-fee shape are taken from the Ophis SDK (@ophis/sdk); appData hashing and the approve / setPreSignature ABI encoding are unit-verified.
  • Two items to validate against live endpoints (documented in references/api.md): (a) the orderbook accepting signingScheme: "presign" with an empty signature on each target chain, and (b) Bankr's exact /agent/submit success/response shape. All HTTP failures are fail-closed (the script exits; no partial fund movement).
  • No native-token path — native ETH sells and buys are rejected (buy WETH and unwrap).

Happy to iterate on anything.

Same-chain token swaps routed through Ophis (CoW intent settlement): batch-auction
best execution, surplus returned to the trader, gasless for the user. Executes from
a Bankr wallet via the presign scheme — approve the VaultRelayer and authorize the
order on-chain with setPreSignature, both through the Bankr Submit API. Complements
the bridging skills (same-chain, not cross-chain). Adds ophis/ + README row.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
san-npm pushed a commit to ophis-fi/ophis that referenced this pull request Jul 13, 2026
… from, reject reverted submits

Addresses PR #815 Codex review:
- Sign the GROSS sellAmount with feeAmount 0 (P1): the order echoed the quote's
  net sellAmount + feeAmount, which the orderbook rejects for a non-zero fee and
  under-sells otherwise. Bind gross (sellAmount + feeAmount) == requested; require
  the quote fields present; self-set validTo.
- Quote with signingScheme presign (P2) to match the submitted presign order, and
  send the appData HASH (not the full JSON, which the strict schema 400s).
- ophis-quote.py: use a non-zero from (CoW zero-address deny-list); optional
  trader-address override.
- bankr_submit: reject a reverted/failed status instead of treating any returned
  transactionHash as success (P2).
- Document the best-effort enroll_wallet empty except.

Deferred (need external verification, not doable from here): migrating off the
Bankr /agent/* endpoints to /wallet/* (must be checked against the current Bankr
API — same review applies on upstream BankrBot/skills#563), and a USDT-style
allowance reset (this presign path has no allowance read; needs an RPC read or a
known-nonstandard-token list).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
san-npm pushed a commit to ophis-fi/ophis that referenced this pull request Jul 13, 2026
The legacy /agent/balances and /agent/submit endpoints were REMOVED from the
Bankr API (confirmed against BankrBot/skills SKILL.md + references/sign-submit-api.md),
so the skill could not resolve a wallet or submit a tx on the current API.

- bankr_wallet_address: GET /wallet/me (was /agent/balances). Extracts the first
  0x EVM address across the plausible keys (evmAddress/address/evm/wallet/
  addresses.*) and validates the 0x40-hex shape, so it never picks Bankr's Solana
  address. Dropped the now-unneeded chain-slug arg + BANKR_SLUG map.
- bankr_submit: POST /wallet/submit (was /agent/submit). Identical body. Status
  handling aligned to the documented values success|reverted|pending: reject
  reverted, require an explicit success, and refuse an unconfirmed pending
  (never accept a bare hash when a status is present).
- Updated SKILL.md + references/api.md to the /wallet/* endpoints.

Verify against a live GET /wallet/me for the exact EVM-address key. Same change
must be mirrored to upstream BankrBot/skills#563.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sync from the ophis-fi/ophis source of truth (reviewed via Codex):
- Migrate off the removed /agent/balances + /agent/submit to GET /wallet/me and
  POST /wallet/submit (identical submit body). Resolve the EVM wallet address by
  0x-40-hex format (never a Solana address). Submit status handling rejects
  reverted, refuses an unconfirmed pending, and only accepts a bare tx hash when
  no status field is present.
- Sign the GROSS sellAmount with feeAmount 0 and bind gross == requested (CoW/
  Ophis take the fee from surplus + the appData partner fee; the orderbook rejects
  a non-zero signed feeAmount). Self-set validTo; require quote fields present.
- Quote with signingScheme presign (matches the submitted presign order) and send
  the appData hash (the strict schema 400s the full doc on a referral'd quote).
- ophis-quote.py: non-zero from (CoW zero-address deny-list), optional trader arg.
- _http: https scheme guard; validate the 0x address before it enters the enroll URL.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
san-npm added a commit to ophis-fi/ophis that referenced this pull request Jul 13, 2026
* feat(integrations): Bankr skill scaffold — Ophis MEV-protected same-chain swap

A plug-and-play Bankr Skill (SKILL.md + catalog.json + scripts + references)
that lets Bankr AI agents execute MEV-protected same-chain swaps through Ophis
(CoW Protocol intent settlement) from a Bankr-managed wallet.

Flow: quote -> build Ophis partner-fee appData -> PUT app_data -> approve the CoW
VaultRelayer via the Bankr Submit API -> POST a presign order -> authorize it
on-chain with setPreSignature via Bankr Submit. Uses the presign scheme so the
Bankr wallet only submits transactions (no raw message-signing). Monetized via the
appData partnerFee (recipient = Ophis Safe; optional ophisReferrer code = rebate).

Endpoints/addresses/appData shape are grounded in @ophis/sdk (see references/).
appData hashing + approve/setPreSignature ABI encoding verified locally. Positioned
as same-chain best execution — complementary to the bridging skills (symbiosis/trails).
Not yet submitted to BankrBot/skills (review first).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(bankr-skill): harden per internal security audit (fund-safety + fee-routing)

3-lens adversarial audit (fund-safety / fee-routing / protocol-correctness) of the
Ophis swap skill, all findings remediated + re-verified (PASS):

- HIGH: approve() was sent to the VaultRelayer instead of the ERC-20 sell token
  (spender was right, tx target was wrong) → no allowance, order unfillable. Fixed:
  tx `to` = sell token; spender stays the relayer.
- HIGH: slippage_bps was unbounded → min_buy could floor to 0 (accept-any-price /
  max-sandwich). Fixed: reject slippage outside [0,5000] and refuse min_buy<=0.
- HIGH: a network error to the rebate indexer crashed the whole swap (_http only
  caught HTTPError; enroll_wallet only caught SystemExit). Fixed: _http catches
  URLError/timeout (fail-closed); enroll_wallet is truly best-effort (except Exception).
- MED: the signed order now echoes the quote's sellAmount/feeAmount (approve covers
  both), matching the @ophis/sdk reference, instead of raw input + hardcoded fee 0.
- MED: referral codes are validated against ^[a-z0-9_-]{3,64}$ and fail loudly, so an
  unmatchable code can't silently forfeit the rebate.
- MED: bankr_submit also accepts a returned transactionHash as success.
- LOW: exact EIP-7528 native sentinel match (both sell and buy side); SKILL.md step
  order fixed (POST order -> setPreSignature); stable-pair fee behavior documented.

Green: py_compile + appData-hash/ABI/referral smoke tests pass. Not pushed to
BankrBot/skills — internal review only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* bankr: sign feeAmount 0 + gross, presign quote scheme, non-zero quote from, reject reverted submits

Addresses PR #815 Codex review:
- Sign the GROSS sellAmount with feeAmount 0 (P1): the order echoed the quote's
  net sellAmount + feeAmount, which the orderbook rejects for a non-zero fee and
  under-sells otherwise. Bind gross (sellAmount + feeAmount) == requested; require
  the quote fields present; self-set validTo.
- Quote with signingScheme presign (P2) to match the submitted presign order, and
  send the appData HASH (not the full JSON, which the strict schema 400s).
- ophis-quote.py: use a non-zero from (CoW zero-address deny-list); optional
  trader-address override.
- bankr_submit: reject a reverted/failed status instead of treating any returned
  transactionHash as success (P2).
- Document the best-effort enroll_wallet empty except.

Deferred (need external verification, not doable from here): migrating off the
Bankr /agent/* endpoints to /wallet/* (must be checked against the current Bankr
API — same review applies on upstream BankrBot/skills#563), and a USDT-style
allowance reset (this presign path has no allowance read; needs an RPC read or a
known-nonstandard-token list).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* bankr: https scheme-guard in _http + validate wallet in enroll (semgrep)

Add the https:// scheme guard the sibling adapter cores already have (blocks
file://, http://), validate the 0x-address before it enters the enroll URL path,
and annotate the two urllib calls (URLs are scheme-guarded + built from fixed
https maps). Clears the semgrep dynamic-urllib findings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* bankr: single explicit return in _http (no implicit None fall-through)

Addresses the Codex PR #815 review: _http is typed -> dict but returned inside the
try while the except branches sys.exit; a naive analyzer that does not model
sys.exit as NoReturn sees a possible implicit return None. Move the parse to a
single trailing return so no path can fall through to None.

* bankr: migrate to the current Wallet API (/wallet/me, /wallet/submit)

The legacy /agent/balances and /agent/submit endpoints were REMOVED from the
Bankr API (confirmed against BankrBot/skills SKILL.md + references/sign-submit-api.md),
so the skill could not resolve a wallet or submit a tx on the current API.

- bankr_wallet_address: GET /wallet/me (was /agent/balances). Extracts the first
  0x EVM address across the plausible keys (evmAddress/address/evm/wallet/
  addresses.*) and validates the 0x40-hex shape, so it never picks Bankr's Solana
  address. Dropped the now-unneeded chain-slug arg + BANKR_SLUG map.
- bankr_submit: POST /wallet/submit (was /agent/submit). Identical body. Status
  handling aligned to the documented values success|reverted|pending: reject
  reverted, require an explicit success, and refuse an unconfirmed pending
  (never accept a bare hash when a status is present).
- Updated SKILL.md + references/api.md to the /wallet/* endpoints.

Verify against a live GET /wallet/me for the exact EVM-address key. Same change
must be mirrored to upstream BankrBot/skills#563.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* bankr: format-based /wallet/me address + strict submit status (Codex)

- bankr_wallet_address resolves the EVM address by 0x-40-hex FORMAT (named keys
  then a top-level scan), guarded on a dict response, so it needs no exact-key
  knowledge, never returns a Solana address, and errors cleanly on a non-object
  response.
- bankr_submit rejects status 'pending' before any success check (an unconfirmed
  approval/presign is refused even if success:true), and only falls back to a
  bare transactionHash when NO status/state key is present.

Codex (gpt-5.6-sol): pass. semgrep clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
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