Bot Titles
PLS-ATOMIC-ARB-V1Performance So Far
PLS-ATOMIC-ARB-V1Recent Fire Attempts
PLS-ATOMIC-ARB-V1Token Reverters (24h)
PLS-ATOMIC-ARB-V1Biggest Block
PLS-ATOMIC-ARB-V1BENCHED (~2026-05-19): 0 wins lifetime, 5 broadcasts ever (last fire 2026-05-13), contract drained to 0 WPLS so it can no longer fire. The diagnosis below is the historical record from when it was active — three blocks that were never solved before the contract was swept:
• Pool reserves move between when the scanner quotes a spread and when the contract simulates it. The V2 pair's constant-product invariant ("NineInch: K") then fails. Sim-time re-quote (shipped) tests whether this collapses the drift window enough to land trades.
• The on-chain slippage cushion was 50bps — too tight for PulseChain's block-spanning reserve volatility. Widened to 200bps today. If K-invariant reverts persist, widen further.
• Signals were up to 12s old at sim time; PulseChain blocks are ~10s, so a signal could span a block boundary before the bot acted. Tightened to 8s today.
The sim-revert histogram (89% K-invariant-class, 22,317 of 25,093 signals) confirms block #1 dominated. None were solved before the contract was drained. Any revival must inherit the 2026-07-02 inclusion-latency stack (sentinel dual-broadcast, 50 peers, multi-RPC) and be measured on land-rate — re-running it as-is would just reproduce the same race loss.
Fantasy
PLS-ATOMIC-ARB-V1If we could simulate a multiSwap at the EXACT same block height it will execute at — instead of the current callStatic at latest block with state drift between sim and submission — every sim that passes would land. The closest real-world thing: pulse-sentinel's outgoing-tx bundle relayer already targets specific builders (PRIVATE_EXECUTION_CONFIG.TARGET_BUILDER_RPCS), so we know which block our tx is aimed at. If the relayer exposed a block-targeted callStatic endpoint (sim at the exact block height where it submits), the sim/live drift gap that today reverts every fire would collapse. Builders sell this as MEV-Boost-style preconfs on other chains; PulseChain has no native preconf market yet but the sentinel could fake it locally by simulating against the mempool tip + own bundle. Hours of work to plumb but unlocks the only thing currently blocking this bot from earning.
Suggestions for Improvement
PLS-ATOMIC-ARB-V1- 01CRITICALPre-broadcast freshness probe. Between sim and bundle submit, do one more getReserves() on both pools. Abort if reserves moved >10bps since sim. Today's 2 [LOSS] events were sim-pass-then-state-moved. Closes the last drift window.
- 02HIGHDecide capital redirect at 2026-05-16 (48h gate). If still 0 wins, move ~6M WPLS from this contract to AGG-ARB's AtomicArb (currently 567K) — where capital actually compounds. Keep ~1M here as test ammo. Reversible: a new V3 contract deploy is cheap.
- 03HIGHAdd unknown_selector entries to CONTRACT_ERROR_SELECTORS as they appear in the histogram. The 9mm V3 SwapRouter and V3 pool itself almost certainly emit custom errors we haven't mapped. Each new entry tightens the diagnostic loop.
- 04HIGHOnce the histogram shows the dominant cause, deploy the matching fix: K_invariant → widen slipFactor further (9800n → 9700n). V3SlippageHit → reduce trade size or skip V3 entirely. NoProfit/InsufficientNet → raise scanner spread threshold. One change at a time so we know what worked.
Conclusion
PLS-ATOMIC-ARB-V1Verdict (re-checked 2026-07-02): BENCHED — 0 wins lifetime, last fire 2026-05-13 (~7 weeks ago), contract at 0 WPLS. The contract (0xF538…3826) was deliberately swept from 7.1M → 0 WPLS ~2026-05-19; verified still 0 on-chain 2026-07-02. With no balance, multiSwap pulls firstAmount from an empty contract so every callStatic reverts — hence the 89% sim_revert flood (22,317 of 25,093 signals). The scanner still feeds it, but it cannot fire. The capital question was answered by withdrawal: effectively retired in practice, though no formal decommission flag was ever set (so it still renders green "live"). Retired-bot-revival candidate: re-evaluate whether the 2026-07-02 infra upgrades (peers 17→50, sentinel mempool feed, multi-RPC, hairylabs) change the inclusion-race verdict below before deciding to re-fund or formally retire.
Failure mode #1 — we're losing the race to inclusion without admitting it. The shipped fixes (sim-time re-quote, decoded revert histogram, slippage cushion, verdict gate) reduce the loss surface but never addressed the root cause: by the time our atomic multiSwap is mined, somebody else has eaten the spread. This is exactly the failure class the 2026-07-02 inclusion-latency work (sentinel dual-broadcast, more peers, multi-RPC) is built to attack — so IF this bot is ever re-funded, it should inherit that stack and be measured on land-rate, not re-run as-is.
Failure mode #2 — the comparison set is unfair. PLS-AGG-ARB-V5's pool has the same chain conditions, the same gas, the same competitors — and it fires. The difference is route construction: V5 leans on aggregator routing where MEV is already priced in; V1 tries to extract the residual spread that aggregators leave behind. That residual may simply not exist post-Piteas/Squirrel maturity.
Failure mode #3 — the opportunity-cost question was already resolved by drainage. The 7.1M WPLS that previously sat in 0xF538…3826 is gone (current balance: 0). Either redeployed elsewhere or operator-side decision. The "should we redirect capital" debate is moot.
Fixable? No — not as encoded. If the 2026-05-16 24h test still shows 0 wins, the answer is not another patch. Redirect 6M WPLS to the AGG-ARB pool today, keep 1M for an honest sentinel-mempool-aware rebuild (use pulse-sentinel's eth_subscribe newPendingTransactions to fire IN the mempool, not after). That is a different bot, not a patch.
Active Tests & Monitors
PLS-ATOMIC-ARB-V1| Test / Monitor | Started | Key Metric | Decision Criteria |
|---|---|---|---|
| Verdict gate integration (NEW 2026-05-14) | 2026-05-14 | Reject count by verdict_blacklist vs verdict_blacklist_unverified, vs sim_revert. Need a [V_BLOCK] log to count cleanly. | Gate fires before any sim. Lets the same classifier that protected PLS-AGG-ARB on 2026-05-13 also shield this bot. Watch: how many of the next 100 signals get rejected at the gate vs at sim_revert. |
| sim_revert root cause diagnosis | 2026-04-30 (live) | Decoded revert reason — "NineInch: K" is the constant-product invariant on the 9inch V2 pair. Other reverts show "missing revert data" (no custom error decoded). | NineInch: K = reserves moved between scanner quote and sim time. Two fixes possible: (a) decode all custom errors (RouterMath, K, etc.) so we can categorise, (b) shorten scanner→sim latency. Until decoded, every sim is a blind probe. |
| TX outcomes (5 broadcast lifetime) | 2026-04-30 | Bot log [TX] count = 5, [LOSS] count = 2, [WAIT_ERR] count = 3, [WIN] count = 0. Trade log has 1 entry (success: false). | Of the 5 broadcasts ever, none won. The 3 WAIT_ERR were submission failures (relayer error). The 2 LOSS were tx mined but realized WPLS ≤ 0. Need: success rate of the 9mm V2 → PulseX V2 route specifically before claiming the strategy is viable. |
| Signal volume | 2026-04-30 | 694 signals in logs/pls-v3-overlap-spreads.ndjson lifetime. ~49 signals per day average. Recent signals all 100K WPLS size, 37–49 bps spreads. | Plenty of inbound signal — the scanner is finding real-looking opportunities. Bottleneck is downstream: 160 [SIG] events ingested in the most recent log window vs 5 [TX] (3% landing rate from signal to broadcast). |
| Contract balance (drained) | 2026-04-29 (deploy) | WPLS.balanceOf(0xF538…3826) = 0 (re-verified on-chain 2026-05-27; still 0) | ✅ DIAGNOSIS COMPLETE — drain confirmed 0 WPLS still. Bot is signal-capture-only. URG-006 operator capital decision is the gate: either refund (probably 50K-100K WPLS for a meaningful live test) or formally retire FullV3 + redirect WPLS elsewhere. |
| Probation graduation | 2026-05-14 | logs/pls-token-probation.json — per-token win/loss counter, tier graduation. | Probation gate is wired but has never fired on this bot (no successful trades since gate landed). Will activate the first time the bot lands a trade on an UNCLASSIFIED token. |
| Bundle relayer health | 2026-04-30 | Per-RPC submission results in perRpc array (logged on each [TX]). Failures show as [RELAY_FAIL]. | ✅ COMPLETE 2026-05-27 — Verified 0 [RELAY_FAIL] entries lifetime. Bundle relayer health validated. If a future RELAY_FAIL emerges, re-open. Losses (when bot has capital to fire) are chain-level, not submission-level. |
Compromises
PLS-ATOMIC-ARB-V1| Decision | Aggressive ← | Current Position | → Conservative | Notes |
|---|---|---|---|---|
| Spread degradation tolerance (LIVE_HAIRCUT_BPS = 9900) | Tight · reject any drift | Loose · trust scanner quote | Tightened 2026-05-14 from 9700 → 9900 (3% → 1%). Now only signals whose fresh re-quote is within 1% of the scanner quote survive. Previous setting let every signal through to sim, where they all hit NineInch: K. Tighter prefilter reduces wasted RPC; recalibrate again once sim_revert histogram is built. | |
| On-chain slippage cushion (slipFactor = 9950n) | Tight · maximum profit capture | Wide · absorb pool drift | Line 252 of fullv3-executor.js applies 50bps slippage to V2 amountOut. Mirror of LIVE_HAIRCUT but at the contract-encoding layer. Today this is the wall causing K-invariant reverts: pool moves 1-2% between executor entry and sim time but contract requires actual ≥ 0.995× quoted. Pending decision after first decoded-revert batch lands; widen to 9800n (2%) if K-invariant dominates the histogram. | |
| Verdict gate + [V_BLOCK] telemetry | Trust all tokens | Blacklist defensive | Added 2026-05-14. Every intermediate token routed through tokenVerdict.getVerdictTag. BLACKLIST + BLACKLIST_UNVERIFIED reject before sim is built (logged as [V_BLOCK]). UNCLASSIFIED enqueues for the daemon + clamps to 50K probation cap. Protects from the BLOB/T⭕KÉ/TEVE/SPX-class honeypots that hit AGG-ARB. Counting [V_BLOCK] vs sim_revert separates "scam exposure" from "strategy timing" failure modes. | |
| Sim-revert decode (CONTRACT_ERROR_SELECTORS map) | Truncated wrapper · debug-blind | Decoded reason · actionable | Added 2026-05-14. 11 contract custom errors + 9 string-substring patterns (NineInch:K, UniswapV2:K, V3 SPL/STF/TLU/L, TransferHelper). Walks e.data / e.error.data / e.error.error.data / parsed error body. Returns categorical labels (K_invariant_9inch, V3SlippageHit, NoProfit, etc.) instead of "call revert exception". Unlocks the diagnostic loop. | |
| Signal freshness (SIGNAL_MAX_AGE_MS = 12000) | Tight · only fresh signals | Loose · burn through any signal | Ignores scanner signals >12s old. With PulseChain ~10s block time, this allows signals that span a block boundary at sim time — the source of most K-invariant reverts. Should tighten to 5000ms after sim-time re-quote (Suggestion #1) lands, but doing both at once would confound which fix worked. | |
| Pool re-quote timing (scanner-time) | Re-quote at sim · 0ms drift | Re-quote at signal · 12s drift | Today readPoolFresh runs at tryExecute entry, then calldata is built + sim runs ~1-2s later. The reserves can move during that 1-2s window AND across the 10s signal-to-tryExecute gap. Pending Suggestion #1: collapse to a single getReserves() immediately before sim, with <500ms tolerance. Highest-leverage change in the bot. | |
| Max trade size (MAX_TRADE_SIZE_WPLS = 200M) | Small · bounded per-tx loss | Huge · capital-efficient when winning | 200,000,000 WPLS (~$1,520) hardcoded cap. Probation gate further clamps fresh tokens to 50K WPLS until 3 wins/tier. The 200M cap only matters once probation graduates a token to tier 3. | |
| Min net profit floor (MIN_NET = 100 WPLS) | Low · catch thin arbs | High · only fat arbs | PRIVATE_EXECUTION_CONFIG.minNet ~$0.0008. Very low because the bot has 0 wins; lowering further wouldn't help when every fire reverts. Raise to 500-1000 once landings are reliable. | |
| Builder bribe (BRIBE_BPS = 1500) | Keep profit · less builder priority | Bribe heavy · land first | 15% of profit to the builder via bundle relayer. Standard mid-range bribe. Tunes inclusion-rate vs net-profit ONCE the bot starts landing trades — irrelevant today. | |
| Submission path (private relayer fan-out) | Public · sandwich-able | Private · hidden until inclusion | PRIVATE_EXECUTION_CONFIG.rpcs has 2 builder endpoints (rpc.pulsechain.box + rpc.pulsechain.com), fan-out parallel via relayer.sendBundle. Falls back to single-RPC ethers.Contract.send if relay returns no hash. 0 [RELAY_FAIL] events lifetime — relayer is healthy. | |
| Rate cap (MAX_TRADES_PER_HOUR = 10) | Strict · bounded downside | Uncapped · max opportunity capture | Inert: bot has 5 lifetime [TX] events across 14 days. Only matters if/when fixes unblock sim-pass rate. | |
| Kill-switch (KILL_AFTER_LOSSES = 5) | Trigger-happy | Resilient | Halts at 5 consecutive losses. Currently 2/5. Reset requires process restart. Tight given the bot has never had a meaningful win streak to draw breathing room from. | |
| Capital deployment (0 WPLS, drained) | Conservative · safety reserve | Aggressive · all-in for max compounding | Contract drained at some point in the last two weeks (was 7.1M). The redirect debate is now moot — funds have already been moved. Bot continues to run signal capture but cannot fire without re-funding. |
Parameters
PLS-ATOMIC-ARB-V1| Parameter | Value | Reasoning | Potential Adjustment(s) |
|---|---|---|---|
| MAX_TRADE_SIZE_WPLS | 200,000,000 WPLS | Per-tx ceiling (200M WPLS ≈ $1,520 at current PLS price). Set very high; the contract balance (7.1M) is the effective cap. Probation gate further clamps fresh tokens to 50K WPLS. | No tuning needed at the contract-cap level. If/when probation graduates a token to tier 3 (200K WPLS, the AGG-ARB ladder max), the real ceiling will be the scanner's signal size, not this. |
| LIVE_HAIRCUT_BPS | 9700 (3% degradation allowed) | Reject if fresh re-quote yields amountOut < scanner_quote × 0.97. Permissive — sim still reverts downstream with NineInch: K, suggesting reserves drift further between sim and submission than this haircut accounts for. | Tighten to 9900 (1%) once the sim_revert reasons are properly decoded. Tightening earlier would just reduce signal volume without fixing root cause. |
| MIN_NET_WPLS | 100 WPLS (~$0.0008) | PRIVATE_EXECUTION_CONFIG.minNet — minimum net profit after gas. Currently very low because the bot has never landed a trade; loosening doesn't help if every fire reverts. | Raise once landings are reliable so we only fire on margin-worthy spreads. |
| BRIBE_BPS | 1500 (15%) | PRIVATE_EXECUTION_CONFIG.bribeBps — share of profit going to the builder via bundle relayer. Standard mid-range bribe. | Raise if inclusion rate is poor once trades start landing. Drop toward 500 if landing rate is good. |
| GAS_LIMIT | 5,000,000 | PRIVATE_EXECUTION_CONFIG.gasLimit — generous ceiling for 2-hop V2↔V3 multiSwap. Each hop ≈ 200K gas + V3 swap overhead. | Lower to 2-3M once we have a baseline of actual gasUsed per successful trade. Today's log only has reverts to measure against. |
| MAX_TRADES_PER_HOUR | 10 | Bot-side rate cap, separate from contract gate. With 5 lifetime [TX] events spanning ~14 days, this cap has never engaged. | Inert until/unless the bot starts firing >10/hr. |
| KILL_AFTER_LOSSES | 5 consecutive | Bot halts after 5 consecutive [LOSS] events. Currently at 2/5; one more would put it on the edge. | Raise to 10 once landings are reliable (sim_revert pattern means most failures don't even reach [LOSS]). Drop to 3 if we want a tighter circuit breaker. |
| SIGNAL_MAX_AGE_MS | 12000 | Discards signals older than 12s. Combined with 2s poll interval, the bot processes at most 6 signals per scanner-output before re-checking. Keeps state fresh. | Reduce to 6-8s if scanner cadence speeds up. Increase to 20s only if signal volume is starving (not the case — 694 signals lifetime). |
| POLL_INTERVAL_MS | 2000 | How often the bot tails logs/pls-v3-overlap-spreads.ndjson for new signals. 2s is fast enough to catch the 12s freshness window 6x per cycle. | Lower to 1000 if we want even tighter signal-to-fire latency, at the cost of CPU. |
| TARGET_BUILDER_RPCS | 2 endpoints | PRIVATE_EXECUTION_CONFIG.rpcs — bundle relayer fans out to these. Currently rpc.pulsechain.box + rpc.pulsechain.com. | Add more PulseChain RPCs that accept bundle submissions to improve inclusion racing. Audit which ones actually mine the bot's bundles vs just accepting and dropping. |
| MAX_GAS_PRICE_GWEI | 1,500,000 | Absolute ceiling on gasPrice. PulseChain gwei is much higher than mainnet (multi-K-gwei base is normal). 1.5M is far above current ~600K-1.5M observed range; effectively no ceiling today. | Tighten to 2× recent p85 once we have win-rate data tied to gas paid. |
| Verdict gate (NEW 2026-05-14) | ACTIVE | tokenVerdict.getVerdictTag on intermediate token. BLACKLIST/BLACKLIST_UNVERIFIED reject before sim. UNCLASSIFIED enqueues classifier job + clamps size to probation cap. Same gate as PLS-AGG-ARB. | No tuning — gate behavior is owned by lib/token-verdict.js + lib/token-probation.js. Add a [V_BLOCK] log entry to count rejections cleanly. |
| Probation cap (NEW 2026-05-14) | 50K / 100K / 200K WPLS | tokenProbation.getMaxSize returns 50K for UNCLASSIFIED+WATCH, graduates after 3 wins/tier. Bot clamps firstAmount + re-quotes both hops at clamped size before callStatic. | Tiers configurable in lib/token-probation.js TIERS array. Don't raise the 50K initial cap until a known-safe pre-flight tax probe is added. |
| Contract balance | 0 WPLS (drained) | PulseAtomicArbV3_FullV3 at 0xF538…3826. Was 7.1M WPLS; verified on-chain 2026-05-21 = 0. Drained at some point in the last 2 weeks (no record of which day or destination in dashboard logs). | Bot cannot fire without re-funding. Decision: re-fund + invest in fixing sim_reverts, OR formally retire the slot. |