DEV Community

Cover image for What Actually Happens When You Swap Tokens on a DEX?

What Actually Happens When You Swap Tokens on a DEX?

A DEX can look deceptively simple from the frontend.

Select two tokens, enter an amount, click Swap, approve the transaction, and wait.

Underneath that button, however, several systems are working together:

User
│
▼
Wallet
│
▼
DEX Frontend
│
▼
Router / Smart Contract
│
├── Liquidity Pool
├── Token Contracts
└── Pricing Logic
│
▼
Blockchain
│
▼
Event Logs
│
▼
Indexer

Understanding this flow is useful because a DEX is not simply a UI connected to a smart contract.

It is a distributed trading system where pricing, liquidity, execution, settlement, and indexing all have different responsibilities.

Start With the Liquidity Pool

Consider a simple ETH/USDC pool.

The pool contains:

ETH → 10
USDC → 30,000

A trader wants to swap ETH for USDC.

In an AMM-based DEX, the trade does not need to find another trader willing to take the opposite side.

The trader interacts with the liquidity pool itself.

Liquidity providers supply the assets, and the AMM determines the exchange rate according to its pricing function.

A simplified constant-product model is:

x × y = k

Where:

x = reserve of token A
y = reserve of token B
k = invariant

Before the trade:

10 ETH × 30,000 USDC
= 300,000

Suppose the trader sends 1 ETH into the pool.

The new ETH reserve becomes:

x' = 11 ETH

The AMM needs to maintain the invariant:

11 × y' = 300,000

Therefore:

y' ≈ 27,272.73 USDC

The difference between the old and new reserves represents the amount of USDC that can be removed from the pool, before fees and other implementation details are applied.

This is the basic idea behind an AMM.

The important part is that the pool itself becomes the counterparty.

Price and Execution Price Are Not the Same

This is where things become more interesting.

The displayed price might look like:

1 ETH = 3,000 USDC

But that does not mean a trader can necessarily swap a large amount of ETH at exactly 3,000 USDC.

Why?

Because the trade changes the pool reserves.

A larger trade moves the pool further along its pricing curve.

This creates price impact.

There is also a difference between:

Market price
Quoted execution price
Price impact
Slippage tolerance

A production DEX needs to expose these clearly before the user signs the transaction.

For example:

Input: 1.0 ETH
Expected output: 2,970 USDC
Price impact: 0.8%
Minimum received: 2,940 USDC
Network fee: 0.002 ETH

These numbers are not just UI decoration.

They are part of the transaction safety model.

The Frontend Does Not Execute the Swap

The frontend calculates or retrieves a quote.

It does not ultimately control the token transfer.

The actual state transition happens through smart contracts.

A simplified flow is:

User
│
│ "Swap 1 ETH for USDC"
▼
Frontend
│
│ request quote
▼
Router
│
│ calculate route
▼
Smart Contract
│
│ execute swap
▼
Liquidity Pool
│
│ update reserves
▼
Blockchain State

The wallet signs the transaction.

The blockchain executes it.

The smart contract determines whether the requested operation is valid.

This distinction is important because the frontend should be treated as an untrusted interface.

Anyone can call the contract directly.

The contract itself must enforce the rules.

Token Approvals Add Another Transaction

For ERC-20 tokens, users typically need to authorize a contract to spend their tokens.

This creates an additional step:

User
│
▼
approve()
│
▼
Token Contract
│
▼
DEX Router
│
▼
swap()

So the first interaction with a token may require two transactions:

approve
swap

A production frontend needs to make this state understandable.

Otherwise users may see:

“Transaction successful”

and still wonder why the swap has not happened.

The frontend should distinguish between:

Approval confirmed
Swap pending
Swap confirmed
Swap failed

This is a small UX detail with a large operational impact.

The Router Is Where Things Get Interesting

A simple DEX might execute:

ETH → USDC

But users may not always get the best execution through a single pool.

A router can split or chain trades:

ETH
│
├── Pool A
│
▼
USDC
│
▼
Pool B
│
▼
DAI

Or:

ETH
│
├── 60% → Pool A
│
└── 40% → Pool B
│
▼
USDC

The router's job is to determine how the requested trade should be executed according to the available liquidity and routing logic.

This creates a trade-off.

More sophisticated routing can improve execution, but it also increases:

Gas consumption
Contract complexity
Failure modes
Simulation requirements
Security surface

The cheapest route computationally is not necessarily the route with the best execution price.

What Happens When the User Clicks "Swap"?

Let's follow the transaction.

Step 1: The frontend creates a transaction

The application prepares something conceptually similar to:

to:
DEX Router

method:
swapExactTokensForTokens()

parameters:
amountIn
amountOutMin
path
recipient
deadline
Step 2: The wallet asks for authorization

The user reviews the transaction and signs it.

The wallet produces a cryptographic signature proving that the account authorized the transaction.

Step 3: The transaction reaches the network

The transaction is broadcast to the blockchain network.

At this point it is not necessarily finalized.

It may be:

Pending
↓
Included in block
↓
Executed
↓
Confirmed / finalized

The frontend therefore needs to handle asynchronous transaction state rather than assuming that submission equals completion.

Step 4: The smart contract executes

The router calls the required contracts.

The transaction may involve:

Router
↓
Token A
↓
Pool
↓
Token B

Each contract call changes blockchain state.

If any required condition fails, the transaction reverts.

What Happens Inside the Pool?

The pool receives the input token.

Then the contract calculates how much output can be released while respecting its pricing rules.

Conceptually:

Before:

Token A reserve = 10
Token B reserve = 30,000

    ↓
Enter fullscreen mode Exit fullscreen mode

Trader sends Token A

    ↓
Enter fullscreen mode Exit fullscreen mode

AMM calculation

    ↓
Enter fullscreen mode Exit fullscreen mode

After:

Token A reserve = 11
Token B reserve = ~27,272

The exact calculation depends on the AMM implementation.

Real protocols may also account for:

Trading fees
Concentrated liquidity
Multiple price ranges
Dynamic fees
Different invariant designs

So the simple x × y = k model is useful for understanding the concept, but it is not a complete representation of every modern AMM.

Where Do Liquidity Providers Fit?

The pool needs liquidity.

Liquidity providers deposit assets into the protocol and receive a claim representing their share of the pool.

Conceptually:

Liquidity Provider
│
├── Token A
└── Token B
│
▼
Liquidity Pool
│
▼
Traders

In return, LPs can receive a portion of trading fees according to the protocol's rules.

But providing liquidity is not risk-free.

LPs can be exposed to:

Impermanent loss
Smart contract risk
Asset volatility
Oracle risk
Protocol-specific risks

From an engineering perspective, liquidity is therefore not simply a feature.

It is part of the protocol's economic design.

The Blockchain Is the Source of Settlement Truth

After the transaction executes, the blockchain contains the resulting state.

For example:

Trader
↓
-1 ETH
+2,970 USDC

Pool
↓
+1 ETH
-2,970 USDC

The DEX frontend should not invent this state.

It should derive it from blockchain data.

That creates an important architecture:

Blockchain
│
├── Transactions
├── Events
└── Contract State
│
▼
Indexer
│
▼
Application DB
│
▼
DEX Frontend
Why You Need an Indexer

Reading raw blockchain data directly from the frontend becomes expensive and inconvenient as the application grows.

Consider a trading page that needs:

Historical trades
Token prices
Volume
Liquidity
User positions
Transaction history
Pool activity

You could query the blockchain repeatedly.

But that is not an efficient application architecture.

An indexer processes blockchain events and transforms them into application-friendly data.

For example:

Swap Event
│
▼
Event Listener
│
▼
Indexer
│
▼
Database
│
├── price history
├── volume
├── transactions
└── pool analytics

The blockchain remains the source of truth.

The indexed database becomes the query layer.

That distinction is important.

Events Are Part of the Integration Contract

Smart contracts can emit events such as:

event Swap(
address indexed sender,
uint256 amountIn,
uint256 amountOut
);

The event allows off-chain systems to observe state transitions without repeatedly reconstructing every operation from scratch.

But event processing needs to be designed carefully.

An indexer should account for:

Duplicate processing
Missed events
RPC failures
Chain reorganizations
Reprocessing
Idempotency

For example, processing the same Swap event twice should not create two trades in the database.

This is a distributed-systems problem hiding inside a DeFi application.

Slippage Is a Safety Mechanism

Suppose the frontend quotes:

1 ETH → 3,000 USDC

But market conditions change before the transaction is executed.

The user might receive:

1 ETH → 2,700 USDC

That may be unacceptable.

The transaction therefore includes a minimum acceptable output:

amountOutMin = 2,950 USDC

If the actual output falls below that threshold, the transaction reverts.

This is why slippage tolerance is more than a UI preference.

It becomes a parameter enforced by the smart contract.

The Mempool Creates Another Problem: MEV

There is a gap between:

User signs transaction

and:

Transaction is executed

During that period, the transaction may be visible to actors that can observe pending transactions.

This creates opportunities for Maximal Extractable Value (MEV).

One common example is a sandwich attack:

User's swap
│
▼
Attacker observes transaction
│
├── Buy before user
│
├── User executes at worse price
│
└── Sell after user

The result can be worse execution for the original trader.

DEX design therefore needs to consider:

Slippage limits
Transaction ordering
Private transaction mechanisms
Routing
Liquidity depth

MEV is not purely a smart-contract bug.

It is a consequence of how transaction ordering and public blockchains interact.

Gas Is Part of the Product

A technically correct swap can still provide a poor user experience if the transaction costs too much.

Gas usage depends on factors such as:

Number of contract calls
Storage operations
Routing complexity
Network conditions
Smart contract implementation

A simple swap may require relatively little computation, while a multi-hop or multi-contract transaction can be considerably more expensive.

This creates an important optimization question:

Is the better price worth the additional execution cost?

A routing algorithm that saves a user 5 USDC but costs an additional 8 USDC in gas is not actually improving execution.

The system needs to optimize for net user outcome, not just quoted token output.

Cross-Chain DEXs Add Another Trust Boundary

Supporting multiple blockchains sounds like a frontend feature.

It is not.

A cross-chain DEX may involve:

Chain A
│
▼
Bridge / Messaging Layer
│
▼
Chain B
│
▼
DEX / Liquidity

Now the system depends on additional components:

Bridges
Messaging protocols
Relayers
Multiple RPC providers
Multiple smart contract environments
Cross-chain liquidity

Every new dependency expands the attack surface.

Supporting ten chains is not simply ten times the configuration.

The security model becomes significantly more complex.

The Architecture I Would Start With

For a production-oriented AMM DEX, a reasonable architecture is:

                User
                  │
                  ▼
            Web / Mobile UI
                  │
        ┌─────────┴─────────┐
        ▼                   ▼
     Wallet              API Layer
                            │
                     ┌──────┴──────┐
                     ▼             ▼
                 Indexer       Analytics
                     │
                     ▼
                Application DB

                  Blockchain
                       │
         ┌─────────────┴─────────────┐
         ▼                           ▼
    Router Contract             Token Contracts
         │
         ▼
    Liquidity Pools
Enter fullscreen mode Exit fullscreen mode

Each layer has a specific responsibility:

Frontend → interaction
Wallet → authorization
Smart contract → execution + settlement
Liquidity pool → available liquidity
Blockchain → state + finality
Indexer → queryable blockchain data
Database → application read model
Analytics → aggregated insights

Keeping these boundaries clear makes the system much easier to test, monitor, and evolve.

The Hard Part Isn't the Swap

Writing a basic swap contract is not the hardest part of building a DEX.

The difficult engineering problems appear around it:

How much liquidity is available?
How do we calculate a safe quote?
What happens when the transaction is delayed?
How do we handle failed transactions?
How do we prevent unauthorized actions?
How do we index millions of events?
How do we protect users against bad execution?
How do we manage MEV?
What happens when an RPC provider fails?
What changes when we add another chain?

The swap is only one state transition inside a much larger distributed system.

Final Takeaway

A DEX is best understood as a combination of:

Trading Logic
+
Liquidity
+
Smart Contracts
+
Wallets
+
Blockchain Infrastructure
+
Indexing
+
User Protection

The frontend makes the system look simple.

Underneath it, the protocol has to coordinate pricing, liquidity, authorization, execution, settlement, and off-chain data.

That is why DEX development is less about building a “swap page” and more about designing a reliable financial system around blockchain constraints.

The most important architectural question is not:

“How do we build a token swap?”

It is:

“Which parts of the trading system need to be trustless, which parts can remain off-chain, and how do we keep the two consistent?”

That decision shapes almost every other engineering choice.

For a broader overview of DEX architecture, trading models, development stages, and the infrastructure involved, see SotaTek's DEX Development guide.

Top comments (1)

Collapse
 
denshin profile image
Denshin Team •

the event logs part is underrated. we check swaps from the reading side, and the hard bit wasnt the math, it was knowing which pools and routers to trust. a swap through some random contract emits the same looking events, so we match against a list of known venues