feat(bot): regime-derived profit-proportional bidding + vendor crypto (WP 7913) #19
No reviewers
Labels
No labels
auto-merge
auto-merge
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
fortiblox/arc-mev-bot!19
Loading…
Reference in a new issue
No description provided.
Delete branch "perf/bidding-vendor"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Phase 4 lane, second PR (WP 7913 + the
bot/vendorsigning primitives used by the next PR).bot/bidding.py—Opportunity → Bid, profit-proportional and regime-derived (architecture §2.4/§4.2,docs/research/arc-arb-learnings.md§4.4):TipRegimeingests full blocks (same effective-tip rule asdocs/research/probes/ordering_regime_probe.py), refuses to bid on a cold window (regime_min_blocks, "never tuned once"), andrefresh_from_pooltries the announcing WS source first, then every other read endpoint — a fast WS head is not yet imported by the local node (~120ms lag, measured in PR #15).Gas rate — no duplicate table. Reuses the already-committed
[chain].gas_token_erc20/gas_wei_per_erc20_unit(revenue-director's search config, verified1e12for0x3600…0000) instead of a private[[bidding.gas_rate]]list — one source of truth, an Opportunity on any other base token is a hard error.bot/vendor/(keccak-256, secp256k1 with RFC 6979 + EIP-2 low-s + recovery, RLP) — spec-derived, no third-party code. Rationale inbot/vendor/README.md:cast mktxcosts 189–703 ms per signature on LXC 140 (load ~10, 4 vCPU) vs ~1 ms in-process; CEO-approved 2026-09-16 given a pluggableSignerstill lands (next PR) withCastSigneras the shell-out fallback. Every primitive is pinned tocast-generated vectors (Foundry 1.8.1) plus the EIP-155 spec vector — bit-exact signatures proven in the next PR'stest_submit.py.Property tests (
bot/tests/test_bidding.py): floor ≤ priority ≤ cap, priority ≤ affordable ceiling, margin always kept (net_after_bid > min_profit), monotone in net profit,max_fee > priorityalways, all valuesint. 500 randomized cases over floor/cap/fraction/regime combinations.Test plan
make lint testgreen locally (238 tests, whole repo) and on LXC 140 (Python 3.12.3)bot/tests/test_vendor_crypto.py: keccak vectors vscast keccak; secp256k1 sign/verify/recover vscast wallet sign --no-hash; RLP canonical examples + the EIP-155 spec's own raw tx, round-tripped and re-signed to reproduce its publishedr,s,vconfig/bot.example.toml's[bidding]section itself parses and validates (test_from_dict_and_env_override's final assertion loads the real committed file)🤖 Generated with Claude Code
bot/bidding.py - Opportunity → Bid per architecture §2.4/§4.2 and learnings §4.4: priority = clamp(profit_fraction × net, max(floor, rival_tip_floor × (1+bump)), min(cap, affordable)), affordable = (net − min_profit − 1)/gas so the margin is always kept; max_fee = max(next_base_fee(extra_data) × 1.25, 20 gwei) + priority — never a full-ceiling bid (maxFee == priority). Pure integer math; gas-wei → base units via a configured rational per base token (1/1e12 for 0x3600…0000, verified); unknown base token is a hard error. - TipRegime: rolling window of the last N blocks' index-0/index-k effective tips (same rule as docs/research/probes/ordering_regime_probe.py) and the next base fee from extra_data; a cold window (< regime_min_blocks) refuses to bid ("never tuned once"). refresh_from_pool tries the announcing WS source first and every read endpoint after — a fast WS head is not yet imported by the local node. - Opportunity validation (§2.3, §4.1, §4.4, optional `contention`), opportunity_id, route_key; Bid carries block + registry_hash (§4.8). Config: [bidding] in config/bot.toml, every key required, env ARC_MEV_BIDDING_<KEY> overrides (§4.7). - Property tests: floor ≤ priority ≤ cap, ≤ affordable ceiling, monotone in net profit, margin kept, max_fee > priority, ints only. bot/vendor/ (keccak.py, secp256k1.py, rlp.py, README.md with provenance) - spec-derived, dependency-free primitives the stdlib lacks; pinned to `cast` (Foundry 1.8.1) vectors and the EIP-155 spec vector; RFC 6979 deterministic nonces, EIP-2 low-s, public-key recovery. Rationale: `cast mktx` per tx costs 190-700 ms on LXC 140 vs ~1 ms in-process (measured; CEO-approved). Co-Authored-By: Claude Fable 5.1 <[email protected]> Signed-off-by: BuddySan <[email protected]>automerger v2 auto-approved: all 7 gates pass. Approver: fortiblox-dev (opposite-identity rule). Gates: mergeable=true,label=auto-merge,author=buddysan,identity=ok,status_checks=not_required,signatures=upstream_BP_only,opt_in=repo_marker.
Auto-merged by forgejo-automerger at 2026-09-16 14:51:49 UTC. Approver:
fortiblox-dev(opposite-identity rule, Option C upgrade 2026-05-13). Merger:buddysanviafast-forward-only(NOT adminforce_merge). Criteria passed:mergeable=true,label=auto-merge,author=buddysan,identity=ok,status_checks=not_required,signatures=upstream_BP_only,opt_in=repo_marker. Branchdfc107b29amerged ontomainand feature branch deleted. Seeproject_forgejo_automergermemory for rationale.