Skip to content

fix(swap): execute RFQ swaps on tx.to / order.maker, not the deployments address - #11

Merged
ngurmen merged 2 commits into
mainfrom
mng/rfq-maker-routing
Sep 19, 2026
Merged

ngurmen merged 2 commits into
mainfrom
mng/rfq-maker-routing

Conversation

@ngurmen

@ngurmen ngurmen commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Execute simpleSwap on the quote's tx.to (DexalotRouter) or order.maker, never on the deployments MainnetRFQ address; mainnet firm quotes are signed by one of nine maker contracts behind the router, each with its own swap signer, so the old target reverted with RF-IS-01 whenever another maker won the quote (TradeBots failures 2026-09-18).
  • Discover the router from the deployments endpoint (DexalotRouter, loaded best-effort in initialize_client) with MainnetRFQ.trustedForwarder() as on-chain fallback; read the allowed makers from DexalotRouter.getAllowedRFQs() (static-tier cache, failures degrade to deployment-only and are not cached) and refuse quotes whose maker or tx.to fall outside that set.
  • Cross-check tx.data / tx.value against the simpleSwap call the SDK encodes itself from an embedded ABI fragment.
  • Pre-check the ERC20 allowance on order.maker (the maker pulls funds via transferFrom) and fail with an actionable message; add approve_rfq_maker(quote, amount_wei=None, wait_for_receipt=True).
  • Append [target=, maker=, quote_id=, nonce_and_meta=, expiry=] to swap errors; return target and maker on success.
  • Key MainnetRFQ / DexalotRouter deployments by the connected chain's chain_config name instead of always "Avalanche", so _get_rfq_contract resolves on Fuji (it never did before).
  • Raise aiohttp>=3.14.3, cryptography>=50.0.0,<51, and transitive floors for msgpack, pip and pymdown-extensions so pip-audit passes; bump version to 0.6.1.

Quality Gates

  • make test (1178 passed)
  • pytest --cov-fail-under=100 tests/unit (100.00%)
  • make lint, make mypy (clean)
  • make security (bandit high: 0; pip-audit: no known vulnerabilities)
  • Live read-only discovery against mainnet (router from API, 9 makers on-chain) and Fuji (router from API, 2 makers)

Behavioural changes

  • execute_rfq_swap now makes up to two extra eth_calls per swap for ERC20 sells (allowance) and once per hour for target discovery, and refuses quotes it previously would have sent to the wrong contract.
  • ERC20 RFQ sells require an allowance on order.maker; approvals granted to the legacy MainnetRFQ address do not carry over to other makers.

…nts address

Mainnet firm quotes are signed by one of several maker contracts (legacy
MainnetRFQ 1.2.8 plus DexalotRFQ 2.x instances, each with its own swap
signer) behind DexalotRouter, and the deployments endpoint only lists the
legacy MainnetRFQ and the router. Sending a quote from another maker to
the legacy address reverts with RF-IS-01 (invalid order signature).

execute_rfq_swap now:
- targets the quote's tx.to (the router) or order.maker, never the
  deployments MainnetRFQ address;
- takes the router from the deployments endpoint (DexalotRouter, loaded
  best-effort during initialize_client) with MainnetRFQ.trustedForwarder()
  as on-chain fallback, reads the allowed makers from
  DexalotRouter.getAllowedRFQs() (static-tier cache, failures degrade to
  deployment-only and are not cached), and refuses quotes whose maker or
  tx.to fall outside that set;
- cross-checks tx.data / tx.value against the simpleSwap call the SDK
  encodes itself from an embedded ABI fragment;
- pre-checks the ERC20 allowance on order.maker and fails with an
  actionable message; new approve_rfq_maker(quote) grants it;
- appends [target=, maker=, quote_id=, nonce_and_meta=, expiry=] to swap
  errors and returns target/maker on success.

Also keys MainnetRFQ/DexalotRouter deployments by the connected chain's
chain_config name ("Fuji" on testnet) instead of always "Avalanche", so
_get_rfq_contract resolves on Fuji.

Dependencies: aiohttp>=3.14.3, cryptography>=50.0.0,<51, and transitive
floors for msgpack, pip and pymdown-extensions so pip-audit passes.

Bump version to 0.6.1.
@ngurmen ngurmen closed this Sep 19, 2026
@ngurmen ngurmen reopened this Sep 19, 2026
@ngurmen
ngurmen merged commit 94fe109 into main Sep 19, 2026
3 checks passed
@ngurmen
ngurmen deleted the mng/rfq-maker-routing branch September 19, 2026 09:51
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.

3 participants