Development of JIT (Just-In-Time) Liquidity System
JIT liquidity is an MEV strategy that Uniswap Labs calls "benign MEV" in contrast to sandwich attacks. The mechanics: in the same block as a large swap, a liquidity provider adds concentrated liquidity around the current price, earns fees from that swap, and withdraws liquidity in the same block. Three on-chain operations plus a swap fee in a single transaction.
In November 2022, address 0x0a59... earned $250k in a single month exclusively from JIT. Meanwhile, other LPs in the same pools were losing part of their fee share. The JIT bot literally "inserts" itself before a large trade and intercepts a significant portion of fees.
Why JIT Works: Uniswap v3 Mathematics
Concentrated Liquidity and Fee Share
In Uniswap v3, swap fees are distributed proportionally to liquidity in the active tick range. If at the moment of swap a JIT position added $1M of liquidity in tick range [P-0.1%, P+0.1%], and all other LPs have $500k in this range — JIT receives 1M/1.5M = 66.7% of the fee from that swap.
The strategy is profitable when:
- The swap is large enough (otherwise fees don't cover gas for 3 operations)
- The tick range is narrow enough (higher share, lower impermanent loss during holding)
- The position is held for one block (zero impermanent loss risk)
Minimum swap size for break-even at 0.3% fee tier on Ethereum mainnet (gas ~30 gwei):
-
addLiquidity+removeLiquidity+collect≈ 350k gas ≈ $25 at ETH=$2000 - Need to earn >$25 in fees → swap must be >$8300
On L2 (Arbitrum): the same calculation gives minimum swap ~$500. Significantly more opportunities.
Latency Problem: Block Already Mined
JIT requires seeing the swap in the mempool before its inclusion in a block. Private mempool via Flashbots MEV-Share or public mempool via websocket. Between discovering the transaction and including your bundle — seconds matter.
Optimal infrastructure:
- Own node with MEV-Geth or reth with mempool websocket
- Connection to Flashbots MEV-Share to see hints about pending swaps
- Bundle submission via
eth_sendBundle— atomic inclusion of all three transactions in one block
Without bundle submission JIT doesn't work: if addLiquidity and the swap end up in different blocks — the strategy is pointless and unprofitable.
JIT System Architecture
Off-chain Components
Mempool scanner: WebSocket subscription to a node, filtering Uniswap v3 swaps by exactInputSingle/exactInput selector. Decoding calldata to determine pool, size, and slippage.
Profitability calculator: for each candidate calculates:
- Expected fee =
swapAmount * feeTier - Fee share =
depositAmount / (poolLiquidity + depositAmount) - Bundle gas cost =
(addLiq + removeLiq + collect) * gasPrice - Net profit = (fee * share) - gas
If net profit > threshold ($10–50) — the bundle is sent.
Bundle builder: forms three transactions for Flashbots bundle:
-
tx1:mintposition in the needed tick range -
tx2: original swap (backrun) -
tx3:burn+collectposition
Smart Contract for JIT Operations
Contract wraps liquidity operations and minimizes gas:
function executeJIT(
address pool,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
bytes calldata swapData // original swap calldata
) external onlyOperator {
// tx1: add liquidity
INonfungiblePositionManager(NPM).mint(MintParams({...}));
// tx2: forward swap (in bundle via Flashbots — separate tx)
// tx3: remove liquidity + collect
INonfungiblePositionManager(NPM).decreaseLiquidity(...);
INonfungiblePositionManager(NPM).collect(...);
}
Important: the contract must have sufficient balance of both pool tokens to add liquidity. Balance management is a critical operational aspect: if tokens are imbalanced, some liquidity cannot be added in the desired range.
Tick Range Selection
A narrow range maximizes fee share but increases risk: if the swap moves the price outside the range — the JIT position becomes inactive and stops collecting fees. For a swap without significant price impact (< 0.5%), a range of ±0.3% from current price is sufficient. For large swaps with 1–2% price impact, expand the range to ±2%.
Tick range calculation by price impact:
// tickLower = log(1 - priceImpact) / log(1.0001)
// tickUpper = log(1 + priceImpact) / log(1.0001)
// Plus buffer of 20-30 ticks for safety
Risks and Limitations
Bundle revert risk. If the original swap reverts (e.g., trader's slippage protection), the entire bundle reverts. Gas spent on addLiquidity is lost. Mitigation: include only swaps with soft slippage tolerance (>1%).
Competition with other JIT bots. On highly liquid pairs (ETH/USDC, ETH/USDT) dozens of bots compete for the same swaps. Gas wars through priority fees can eliminate profit. More profitable to target mid-cap pairs where competition is lower.
Uniswap v4 and JIT. With hooks, pools can introduce beforeAddLiquidity hook with minimum holding time — a direct countermeasure against JIT. Several pools are already testing such mechanisms.
Timeline and Process
Development of off-chain components (4–5 days): mempool scanner, profitability calculator, bundle builder with Flashbots integration.
Development of on-chain contract (2–3 days): JIT executor, access control, gas optimization.
Infrastructure (2–3 days): node (reth/geth), MEV-Share integration, monitoring.
Testing (2–3 days): simulations on mainnet fork, back-testing historical swaps to estimate profitability.
Total: 1–2 weeks. Cost is calculated after clarifying target pools and networks.







