affaan-m/ECC · error · SlippageError
Simulation: {actual_out} < {expected_min_out}
Error message
Simulation: {actual_out} < {expected_min_out} What it means
`safe_execute` simulates the call (`eth_call`) and decodes the returned uint256. If `actual_out < expected_min_out`, it raises `SlippageError(f"Simulation: {actual_out} < {expected_min_out}")` and never signs. This is the slippage protection that 594 guards.
Source
Thrown at skills/llm-trading-agent-security/SKILL.md:86
self._record_spend(usd_amount)
```
### Simulate before sending
```python
class SlippageError(Exception):
pass
async def safe_execute(self, tx: dict, expected_min_out: int | None = None) -> str:
sim_result = await self.w3.eth.call(tx)
if expected_min_out is None:
raise ValueError("min_amount_out is required before send")
actual_out = decode_uint256(sim_result)
if actual_out < expected_min_out:
raise SlippageError(f"Simulation: {actual_out} < {expected_min_out}")
signed = self.account.sign_transaction(tx)
return await self.w3.eth.send_raw_transaction(signed.raw_transaction)
```
### Circuit breaker
```python
class TradingCircuitBreaker:
MAX_CONSECUTIVE_LOSSES = 3
MAX_HOURLY_LOSS_PCT = 0.05
def check(self, portfolio_value: float) -> None:
if self.consecutive_losses >= self.MAX_CONSECUTIVE_LOSSES:
self.halt("Too many consecutive losses")
if self.hour_start_value <= 0:
self.halt("Invalid hour_start_value")View on GitHub (pinned to 01e15490f0)
Solutions
- Re-fetch a fresh quote and recompute `expected_min_out = quote * (1 - tolerance)`.
- Loosen slippage tolerance for volatile pairs (but stay within the spend-limit guard).
- Retry with a higher deadline / different route; consider splitting the trade.
- If simulations consistently underperform, investigate the router and pool fee tier.
Example fix
# before
actual_out = decode_uint256(sim_result)
if actual_out < expected_min_out:
raise SlippageError(f"Simulation: {actual_out} < {expected_min_out}")
# after — expose tolerance in the message; suggest a retry bound
slippage_bps = (expected_min_out - actual_out) * 10_000 // expected_min_out
raise SlippageError(
f"Simulation: got {actual_out}, min {expected_min_out} "
f"(negative {slippage_bps} bps); re-quote or raise tolerance"
) Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
for attempt in range(3):
try:
return await agent.safe_execute(tx, expected_min_out=min_out)
except SlippageError as e:
quote = await refetch_quote()
min_out = int(quote * (1 - SLIPPAGE_TOLERANCE))
continue
raise SlippageError('slippage exceeded after retries') Prevention
- Re-quote immediately before execution; do not reuse stale quotes.
- Set slippage tolerance appropriate to the pool volatility.
- Split large trades so per-trade slippage stays bounded.
When it happens
Trigger: On-chain liquidity moved between quote and execution; the simulated return is below the caller's minimum. MEV/front-run reduces the realistic output. Pool fee or route changed.
Common situations: Stale quote used as `expected_min_out`; slippage tolerance set too tight (e.g. 0.1% on a volatile pool); router path is no longer optimal; fee bump from the pool.
Related errors
- Single tx ${usd_amount} exceeds max ${MAX_SINGLE_TX_USD}
- Daily limit: ${daily} + ${usd_amount} > ${MAX_DAILY_SPEND_US
- min_amount_out is required before send
- Potential prompt injection: {text[:100]}
- TRADING_WALLET_PRIVATE_KEY not set
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/806f47205ef9899d.
Report an issue: GitHub.