Can We Return the MEV Left Behind by a Swap to the User?
In 2022, a DeFi swap could finish in seconds. Its economic afterlife did not.
A user makes a large swap through an AMM. The pool's reserve ratio moves, opening a price gap against another DEX. A searcher spots the gap and immediately submits the opposite trade. The two prices that had drifted apart move closer again, and the searcher captures the arbitrage profit.
The market appears to have worked as intended: arbitrage brought prices back into line. But the transaction leaves an uneasy ending for the trader. The user's action created the price gap, and the user paid the slippage and gas. The value created by that trade went instead to whoever followed it fastest.
At the end of 2022, our question began there.
What if the arbitrage did not have to wait outside the user's transaction? Could the protocol capture it first and return the remaining value to the user?
This post revisits that question and the design that followed. At the time, we called it a way to "prevent trading distortion caused by MEV." Several years of research and protocol development have made that language look too broad. More precisely, this design was not a universal solution to MEV. It was an attempt to bring some of the backrun value created by a user's swap inside the transaction itself.
The question began with four pools
Our internal simulation used four constant-product pools containing the same token pair. We assigned simple reserve values to each pool and calculated how to bring their diverging ratios back toward balance after a swap moved one side.
The spreadsheet contained neither a complex market nor a sophisticated searcher competition. It had only the simplest
AMM, with every pool maintaining a * b = k. Yet this small model made one important question unusually clear.
If a user's swap leaves a price difference behind, the protocol executing that swap could perform the offsetting trade before an external arbitrageur closes the gap. If the protocol then returns the resulting net surplus to the user, the same price-recovery process ends with a different allocation of value.
The goal is not to eliminate arbitrage. It is to change who performs it and who receives its proceeds.
From observation to return
At the center of the design is an aggregator that watches two or more DEXs. Translated from the component names in the patent specification into an execution sequence, the flow looks like this:
- Read the reserves and swap prices of the same token pair across multiple DEXs.
- Detect the ratio change caused by the user's swap and the resulting price difference between DEXs.
- Calculate the gross proceeds and every execution cost of a cross-DEX swap.
- Only when the net result is positive, borrow the relatively overvalued token through a flash loan.
- Sell on the DEX where the token is overvalued and buy it back on the DEX where it is undervalued.
- Repay the flash loan and return the remaining net surplus as price improvement or a refund to the user.
A flash loan does not manufacture profit. It provides the liquidity needed to close an existing price gap within one execution flow without requiring the protocol to supply its own capital. If the principal and premium cannot be repaid in the same transaction, the entire execution reverts. This is why the Uniswap v2 flash swap documentation lists arbitrage as a representative use case.
The existence of a price difference is therefore not sufficient. The following value must be positive:
user price improvement = gross cross-DEX arbitrage
- DEX fees
- flash-loan premium
- gas and execution overhead
- protocol fee, if any
A real implementation should stop the entire path when this value falls below its minimum-profit threshold or when the
user's minOut cannot be satisfied.
Working through the numbers
Assume that immediately after the user's swap, two pools containing the same A/B pair have the following state:
| Pool | A reserve | B reserve | Marginal price of A (B/A) |
|---|---|---|---|
| DEX A | 100 | 100 | 1.0 B |
| DEX B | 100 | 120 | 1.2 B |
A is relatively more valuable on DEX B, so a candidate cycle borrows A, sells it on DEX B, and uses the received B to
buy A back on DEX A. With a 0.3% swap fee on both pools, the output for an input amount q is:
gamma = 1 - 0.003 = 0.997
amountOut = reserveOut * gamma * q
/ (reserveIn + gamma * q)
Now assume a 0.05% flash-loan premium and a gas cost valued at 0.01 A. Under these assumptions, the loan size that maximizes net profit is approximately 4.196 A. Rounding it to 4.2 A for readability gives the following calculation:
1. Borrow 4.2 A through a flash loan
2. Swap 4.2 A -> 4.822925 B on DEX B
3. Swap 4.822925 B -> 4.587851 A on DEX A
gross cross-DEX profit 4.587851 - 4.2 = 0.387851 A
flash-loan premium 4.2 * 0.0005 = 0.002100 A
gas cost valued in A 0.010000 A
net surplus returned to user 0.375751 A
The two 0.3% DEX fees are already included in the amountOut calculations. With no protocol fee and all surplus paid
in A, the user receives approximately 0.375751 A in improvement. If the surplus is converted into B, the user's output
token, that conversion's fee and price impact must be included as well.
After the cycle, the marginal price of A is approximately 1.0986 B on DEX A and 1.1053 B on DEX B. The fact that the prices do not become exactly equal is not an error. In a market with fees, a difference smaller than the cost of two swaps is no longer profitable, leaving a no-arbitrage band. This example shows why "maximize net profit after costs" is closer to a real execution condition than "make every pool ratio identical."
Translating the flow into code
Pseudocode that separates pre-execution simulation from onchain execution might look like this:
function swapWithInternalizedArbitrage(order):
snapshot = readEligiblePools(order.pair)
baseline = simulateBestUserRoute(order, snapshot)
candidate = optimizeCrossDexTrade(baseline.postSwapState)
if candidate.netSurplus <= MIN_PROFIT:
return executeBaselineSwap(order, baseline)
result = atomicExecute([
validateQuotes(snapshot, order.deadline),
executeUserSwap(order, baseline.route),
flashBorrow(candidate.borrowToken, candidate.amount),
executeCrossDexTrade(candidate.route),
repayFlashLoan(),
convertSurplusTo(order.tokenOut),
refundSurplus(order.owner),
])
require(result.totalUserOut >= order.minOut)
require(result.totalUserOut >= baseline.userOut)
require(result.flashLoanRepaid)
require(result.netSurplus > MIN_PROFIT)
require(result.unaccountedBalance <= DUST_LIMIT)
Whenever possible, baseline.userOut should be calculated from execution-time state or a signed quote with a bounded
validity period. Otherwise it may become an impossible guarantee when the price moves between simulation and block
inclusion. If refunds are not normalized into the user's output token, comparing totalUserOut also requires a trusted
price reference.
The important part of this pseudocode is not merely that the arbitrage succeeds. The following invariants must hold at the same time:
- The internalized path must not leave the user worse off than the baseline path.
- The flash-loan principal and premium must be repaid in full during the same execution.
- A minimum net surplus must remain after every cost has been deducted.
- Every residual token must be accounted for as a user refund, an explicit fee, or permitted dust.
- If any condition fails, the full path, including the user swap, must revert, or the system must safely fall back to the baseline route.
The equation was a starting point, not the answer
The 2022 model began by naming the two reserves in each pool a_i and b_i:
k_i = a_i * b_i
A = sum(a_i)
B = sum(b_i)
S = A / B
Here, S is a target ratio derived from the aggregate reserves of all reference pools. The model calculates target
reserves that preserve each pool's invariant while moving its reserve ratio toward S:
a_i' = sqrt(S * a_i * b_i)
b_i' = (a_i * b_i) / a_i'
required trade direction and amount = a_i' - a_i
When a_i' - a_i is positive, the pool requires a trade that sends token A into it. When it is negative, the trade
must move in the opposite direction. The idea was to aggregate the required amounts across pools, determine which token
to borrow and how much, execute the cross-DEX swaps, and repay the loan.
The equations are concise. That is also why they carry so many assumptions.
The model assumes fee-free constant-product AMMs. It does not account for concentrated liquidity, different fee tiers,
or stable-swap curves. Nor is S=A/B an external fair price. It is an internal reference derived from the selected
pools, making it sensitive both to pool selection and reserve manipulation. When the price of token A is quoted in B,
the price direction may be the inverse of the reserve ratio, so the notation must be made explicit as well.
It is also not enough to verify that each pool preserves k. The entire path must account for token conservation, the
flash-loan principal and premium, what remains after repayment, and the token in which that remainder is delivered to
the user.
The equations are therefore better understood not as a finished optimization algorithm, but as a first model that reveals where arbitrage exists and in which direction a trade must move.
What it means to bring the trade inside the transaction
Atomicity is the most important boundary of this approach.
If the user swap and the subsequent loan, cross-DEX swaps, repayment, and refund can be combined into a single transaction, an outside participant cannot insert its own transaction between those internal calls. If any profit or repayment condition fails, the entire transaction can revert.
ordering inside the block is controlled by the builder
┌────────────────────────────────────────────────────────────┐
│ attacker transaction: can be placed before the whole path │
├────────────────────────────────────────────────────────────┤
│ our single transaction │
│ quote check -> user swap -> flash borrow -> cross-DEX swap │
│ -> repayment -> user refund │
│ no external transaction can enter between these calls │
├────────────────────────────────────────────────────────────┤
│ attacker transaction: can be placed after the whole path │
└────────────────────────────────────────────────────────────┘
This does not solve transaction ordering as a whole. A builder or proposer can still place another transaction before or after this transaction. If the user's order reaches the public mempool first, frontrunning and sandwiching of the entire transaction remain possible. Atomicity between internal calls and transaction-level ordering protection within a block are different problems.
This is why private order flow, batch auctions, intents, and builder-level protection matter. CoW Protocol uses batch auctions and Coincidence of Wants, while Flashbots addresses private transactions and MEV revenue sharing along a different axis. These designs are not competing versions of one answer; they address different attack surfaces.
A minimal threat model for this design, organized around its execution boundary, looks like this:
| Attack surface | Possible failure | Required defense |
|---|---|---|
| Builder / proposer | Place transactions before or after the entire path, or delay inclusion | Private submission, deadline, minOut, quote-validity checks |
| Shallow or manipulated reference pool | Temporarily change reserves to induce a false target price and trade size | Minimum liquidity, deviation limits, external reference price, per-pool weighting |
| Malicious DEX adapter | Return false values, trigger arbitrary callbacks, or reenter to drain balances | Adapter allowlist, balance-delta accounting, reentrancy guard |
| Stale state | Change reserves after simulation, breaking profitability or repayment conditions | Revalidate at execution, enforce minimum profit, revert the full path |
| Non-standard token | Make expected amounts diverge through fee-on-transfer, rebasing, or callbacks | Restrict supported tokens, settle from actual balance changes, enforce dust limits |
What the contract can directly guarantee is the state transition and balance invariants inside the middle transaction. Order exposure and block ordering outside that boundary require a separate delivery channel and market structure.
Which MEV does this actually reduce?
The design targets a narrow scope:
- Residual arbitrage left across DEXs immediately after a user's swap
- External backrun competition for that arbitrage
- A value-allocation rule in which none of the surplus, after costs, returns to the user
The following problems remain:
- Frontrunning and sandwiching around the entire transaction
- Transaction inclusion, exclusion, reordering, and censorship by builders
- Other forms of MEV, including liquidations and oracle manipulation
- Manipulated reference pools or an incorrect target ratio
- Stale quotes, malicious adapters, callbacks, and reentrancy
- Execution failure when fees and gas exceed the arbitrage profit
This is why we would not repeat the original phrases "prevent MEV damage" or "eliminate slippage" without qualification. A more accurate description is internalization of swap-induced arbitrage. The approach does not eliminate the economic role of arbitrage. It changes the execution path and allocation rule so that its value does not flow only to an external searcher.
This distinction matters from the LP's perspective as well. As the Loss-Versus-Rebalancing paper explains, arbitrage between an AMM and an external market is also connected to LP performance. Returning the arbitrage to the user does not eliminate the underlying adverse selection. The beneficiary may change, but the source of that value must still be measured separately.
The question was not ours alone in 2022
We cannot call this idea the first of its kind. Similar questions appeared elsewhere around the same time.
In August 2022, WOWMAX described executing a swap and arbitrage within one atomic transaction, rebalancing prices across DEXs, and returning the profit to the trader. Later, the UniswapX whitepaper described filler competition, routing, and batching as ways to internalize MEV and return surplus as price improvement.
The implementations differ, but they share one question:
Must the surplus created by a user's order always belong to the fastest searcher?
The small 2022 spreadsheet is interesting not because it contained an exclusive answer. It shows that several designs were converging on the same question, and that a protocol can design not only how an order executes but also who receives the value left behind by that execution.
The patent and the decision to disclose
The design discussed in this post is described in Republic of Korea Patent No. 10-2564770, "Token Swap System and Method Through a Decentralized Exchange for Preventing Transaction Distortion," held by Bankware Global Co., Ltd. The application was filed on January 12, 2023, and the patent was registered on August 3, 2023.
The existence of a patent is neither proof that the technology is complete nor a badge of authority for this post. It is disclosed here to make the source and history of a design that began in 2022 transparent. Nor does this post itself constitute a patent license or a non-assertion pledge. Treating the technology as something closer to a public good would require a separately defined defensive-use policy, patent pledge, or explicit license scope alongside open-source code.
In the blockchain ecosystem, how a patent is used matters more than the mere fact that it exists. The purpose of this record is not to lead with the right itself. It is to disclose the assumptions and limits of the idea so that someone else can build a better model.
Back to the moment after the swap
Return to the question from 2022.
If a price gap remains after the user's swap and someone must close it, who should receive the value created in that process?
This design cannot eliminate MEV. It cannot control every external ordering decision, and a simple reserve ratio should not be mistaken for a fair price. But it presents one clear alternative: the arbitrage created by a user's action need not remain solely a prize for external competition. It can be brought inside protocol execution and returned to the user.
A swap finishes in seconds. Code decides where the value created by that swap ultimately goes.
That was the question we began asking in 2022.