Back to Blog 

Ever wonder how Uniswap manages to handle such a wide variety of token swaps with precision and efficiency? The secret lies in its four distinct swap types, each serving a unique purpose in the DeFi ecosystem. Whether you're a trader looking to optimize your strategies or a developer building on top of Uniswap, understanding these swap mechanics is crucial.
In this deep dive, we'll unpack the complexities of Uniswap's swap functions. Here's what you'll learn:
- The difference between zeroToOne and oneToZero swaps, and why the order matters
- How exactInputForOutput and exactOutputForInput work, and when to use each
- The nuts and bolts of implementing these swap types in your code
- Decoding the SwapParams struct and mastering its use
- Interpreting BalanceDelta results to understand your swap outcomes
- Critical pitfalls to avoid and best practices for secure, efficient swaps
By the end of this guide, you'll have a comprehensive understanding of Uniswap v4's swap mechanics, enabling you to build more robust DeFi applications and make smarter trading decisions. Whether you're looking to optimize your trades, build more efficient DeFi applications, or simply satisfy your curiosity about the inner workings of Uniswap, this guide has got you covered.
Ready to become a Uniswap swap maestro?
Introduction
Before we dive into the details, let's visualize these four swap types. The following diagram illustrates the different combinations of swap directions (zeroToOne and oneToZero) and exactness (exactInputForOutput and exactOutputForInput):
1 Token0 Token12 | |3 | |4 v v5 +----------------+---------------------+6 | | |7 | zeroToOne | exactInputForOutput8 | | ------------------>9 | | |10 | zeroToOne | exactOutputForInput11 | | ------------------>12 | | |13 | oneToZero | exactInputForOutput14 | | <------------------15 | | |16 | oneToZero | exactOutputForInput17 | | <------------------18 | | |19 +----------------+---------------------+
This simple visualization helps us understand the relationship between Token0 and Token1, and how the different swap types operate between them. The arrows indicate the direction of the swap, while the labels describe the type of exactness for each operation.
The basics: zeroToOne and oneToZero
First up, we've got zeroToOne and oneToZero. Sounds like binary code, right? Well, it's actually simpler than that. Remember how Uniswap sorts token pairs? Token0 is always the 'smaller' address, and Token1 is the 'bigger' one. So, zeroToOne means you're swapping from Token0 to Token1, and oneToZero is… you guessed it, the other way around!
Let's look at the actual function signature in Uniswap v4:
1function swap(2 PoolKey memory key,3 SwapParams memory params,4 bytes calldata hookData5) external returns (BalanceDelta);67struct SwapParams {8 bool zeroForOne;9 int256 amountSpecified;10 uint160 sqrtPriceLimitX96;11}
Here,
zeroForOne is a boolean that determines the swap direction. true means zeroToOne, and false means oneToZero.Exactness in swaps: exactInputForOutput and exactOutputForInput
But wait, there's more! We've also got exactInputForOutput and exactOutputForInput. Now, these are where things get interesting.
With exactInputForOutput, you're saying, "Here's exactly how much I want to swap in, give me whatever that's worth in the other token." It's like going to a currency exchange with $100 and saying, "How many euros can I get for this?"
On the flip side, exactOutputForInput is when you say, "I need exactly this much of the output token, take whatever you need of my input token." It's like telling the currency exchange, "I need 100 euros, how many dollars will that cost me?"
In the code, this is represented by the
amountSpecified parameter:1int256 amountSpecified;
If
amountSpecified is positive, it's an exactInputForOutput swap. If it's negative, it's an exactOutputForInput swap.Swap function in-depth
Now that we've got the basics down, you might be thinking: "Okay, but how do I actually use these swap types in my code?"
Great question! Let's roll up our sleeves and dive into some real Uniswap v4 code.
Let's use the cosmic vending machine analogy. In Uniswap v4, the "button" you press to make a swap happen is the
swap function. Let's take another look at the function's parameters:1function swap(2 PoolKey memory key,3 SwapParams memory params,4 bytes calldata hookData5) external returns (BalanceDelta);
-
PoolKey memory key: This is like the address of our vending machine. It tells Uniswap which specific pool we want to interact with. Think of it as saying, "I want to swap between THIS token and THAT token." -
SwapParams memory params: This is where the real magic happens. It's a struct that contains all the details about our swap. We'll dive deeper into this in a moment, but just know that this is where we specify things like which direction we're swapping and how much. -
bytes calldata hookData: This is for any extra data that might be needed by hooks attached to the pool. Hooks are like little add-ons that can modify how the pool behaves. For most basic swaps, you can leave this empty, but it's good to know it's there.
And what do we get back?
A BalanceDelta. This tells us exactly how our balances changed as a result of the swap. It's like a receipt from our cosmic vending machine, showing us what we put in and what we got out.
Now, let's zoom in on that
SwapParams struct. This is where the rubber meets the road in our swap journey...1struct SwapParams {2 bool zeroForOne;3 int256 amountSpecified;4 uint160 sqrtPriceLimitX96;5}
Let's decode this cosmic puzzle:
-
zeroForOne: This little boolean is how we tell Uniswap which direction we're swapping. It's like flipping a switch to decide if we're going from Token0 to Token1 (true), or the other way around (false). -
amountSpecified: This is where we specify how much we're swapping. But here's the twist - the sign of this number (positive or negative) determines whether we're doing an exactInputForOutput or an exactOutputForInput swap. Mind-bending, right? -
sqrtPriceLimitX96: Don't let this scary-looking name fool you. It's just our safety net, making sure we don't get a raw deal if the market moves too much during our swap. (You don't know what this is? Take a look at our glossary on sqrtPriceX96)
Now, you might be wondering, "How do I actually use this to make the four types of swaps we talked about earlier?"
Well, I'm glad you asked! Let's look at some examples:
zeroToOne-exactInputForOutput
Swapping exactly 1 Token0 for as much Token1 as we can get:
1SwapParams memory params = SwapParams({2 zeroForOne: true,3 amountSpecified: 1 ether,4 // Don't do this in production!5 sqrtPriceLimitX96: TickMath.MIN_SQRT_RATIO + 16});
zeroToOne-exactOutputForInput
Swapping for exactly 1 Token1, using as much Token0 as needed:
1SwapParams memory params = SwapParams({2 zeroForOne: true,3 amountSpecified: -1 ether,4 // Don't do this in production!5 sqrtPriceLimitX96: TickMath.MIN_SQRT_RATIO + 16});
Get the DeFi Protocol Security Checklist
15 vulnerabilities every DeFi team should check before mainnet. Used by 30+ protocols.
No spam. Unsubscribe anytime.
See what we did there? We flipped the sign of
amountSpecified to negative, and boom - we've switched from exactInputForOutput to exactOutputForInput!The other two types (oneToZero-exactInputForOutput and oneToZero-exactOutputForInput) follow the same pattern, just with
zeroForOne set to false.Now, after we press that metaphorical button and callswap, what do we get back?
A
BalanceDelta:1struct BalanceDelta {2 int256 amount0;3 int256 amount1;4}
This is Uniswap's way of telling us what actually happened in our swap. If
amount0 is negative, it means Token0 left the pool (we sold it). If it's positive, Token0 entered the pool (we bought it). Same goes for amount1 and Token1.Potential pitfalls and developer considerations
Slippage surprises
Remember that
sqrtPriceLimitX96 parameter we mentioned earlier? It's not just a fancy name – it's your first line of defense against unexpected price movements. In our earlier examples, we set it to the minimum (or maximum) possible value, which is like telling the vending machine "I'll take whatever you give me!" That's fine for examples, but in the real world? Not so much.1// Don't do this in production!2sqrtPriceLimitX96: TickMath.MIN_SQRT_RATIO + 1
Instead, calculate a reasonable price limit based on the current price and your acceptable slippage. It's like setting a "I won't pay more than X" limit on your swap.
Decimal dilemmas
Not all tokens are created equal — at least when it comes to decimal places. Some tokens might have 18 decimal places, others might have 6, or even 0!
When you're swapping between tokens with different decimals, make sure you're accounting for this in your calculations. Otherwise, you might end up swapping 1000 times more (or less) than you intended!
Size matters
Thinking of making a massive swap all at once? You might want to reconsider. Large swaps can have a significant impact on the market, potentially leading to higher slippage and a worse deal for you. Instead, consider breaking your large swap into smaller chunks. It's like eating a whale — you've got to do it one bite at a time!
Gas guzzlers
Keep in mind that exactOutputForInput swaps tend to be more gas-hungry than their exactInputForOutput counterparts. If gas efficiency is a priority (and when is it not?), you might want to lean towards exactInputForOutput swaps where possible.
Error handling
The swap function isn't guaranteed to always succeed. There might not be enough liquidity, or you might hit your price limit. Always be prepared to handle these cases gracefully in your code. Remember, in the world of smart contracts, a failed transaction can still cost you gas!
Hook hazards
If you're working with pools that have hooks attached (which is a whole other can of worms we won't open right now), be aware that these hooks can potentially modify the behavior of your swaps in unexpected ways. Always know what hooks are attached to the pools you're interacting with.
Testing, testing, 1–2–3
Last but definitely not least, test your swap implementations thoroughly. Use a variety of input amounts, different token pairs, and simulate different market conditions. In the world of DeFi, you can never be too careful!
Remember, with great swapping power comes great responsibility. By keeping these considerations in mind, you'll be well on your way to becoming a Uniswap v4 swapping sensation. Happy swapping, and may the liquidity be ever in your favor!
Conclusion
Understanding these swap types isn't just about knowing which function to call. It's about crafting efficient, secure, and user-friendly DeFi applications. Whether you're building the next big DEX aggregator or just trying to get the best deal on your trades, mastering these concepts will serve you well.
Remember, in the world of Uniswap, knowledge is power (and potentially profit). So next time you're setting up a swap, take a moment to consider which direction and exactness works best for your needs. Happy swapping!
Get in touch
At Zealynx, we deeply understand the intricate AMM designs, from concentrated liquidity to the emerging hook architecture and security challenges of protocols like Uniswap. Whether you're building a new DeFi protocol, auditing an existing one, or require expert guidance on the security of your AMM project, our team is ready to assist — reach out.
Want to stay ahead with more in-depth analyses like this? Subscribe to our newsletter and ensure you don't miss out on future insights.
FAQ: Uniswap v4 swap mechanics
1. What is the difference between zeroToOne and oneToZero swaps?
In Uniswap, token pairs are sorted by address, with Token0 being the 'smaller' address and Token1 the 'bigger' one. zeroToOne means swapping from Token0 to Token1 (set
zeroForOne: true), while oneToZero is the reverse direction (set zeroForOne: false). This convention ensures consistent ordering across all pools regardless of how the pair was created.2. When should I use exactInputForOutput vs exactOutputForInput?
Use exactInputForOutput (positive
amountSpecified) when you know exactly how much you want to spend and are flexible on what you receive—like exchanging $100 for however many euros that gets you. Use exactOutputForInput (negative amountSpecified) when you need a specific output amount regardless of cost—like needing exactly 100 euros and paying whatever dollars are required.3. Why are exactOutputForInput swaps more gas-expensive?
exactOutputForInput swaps require additional computation to calculate the precise input amount needed to achieve the desired output. This involves iterating through price calculations until the exact output is reached, whereas exactInputForOutput swaps can compute the output directly from the given input amount.
4. What is sqrtPriceLimitX96 and why is it important?
sqrtPriceLimitX96 is a safety parameter that sets the worst acceptable price for your swap using Uniswap's fixed-point price format. It protects against excessive slippage by causing the transaction to revert if the execution price would move beyond this limit. Never set it to extreme values (MIN_SQRT_RATIO or MAX_SQRT_RATIO) in production as this removes all slippage protection.5. How do I interpret the BalanceDelta returned by a swap?
BalanceDelta contains
amount0 and amount1 representing the net change for each token. Negative values indicate tokens leaving the pool (you sold them), while positive values indicate tokens entering the pool (you bought them). This "receipt" tells you exactly what was exchanged in the swap.6. What are the security risks when implementing Uniswap v4 swaps?
Key risks include: slippage attacks if price limits are too permissive, decimal mismatches between tokens causing incorrect amounts, reentrancy vulnerabilities when hooks are involved, and insufficient error handling for failed swaps. Always validate inputs, set reasonable slippage bounds, understand attached hooks, and test extensively with various market conditions.
Glossary
Quick reference for key terms used in this article:
| Term | Definition |
|---|---|
| Automated Market Maker (AMM) | Decentralized exchange protocol using mathematical formulas to price assets. |
| Hooks | External smart contracts executing custom logic at specific pool lifecycle points. |
| BalanceDelta | Struct returned by Uniswap v4 swaps containing net token balance changes. |
| Exact Input Swap | Swap type where the user specifies exactly how much to spend. |
| Exact Output Swap | Swap type where the user specifies exactly how much to receive. |
| sqrtPriceX96 | Fixed-point number format representing square root of price multiplied by 2^96. |
| Slippage | Difference between expected and actual execution price of a trade. |
| Gas | Unit measuring computational effort required to execute Ethereum transactions. |
Shipping a Uniswap V4 Hook or Integration?
Hooks introduce reentrancy vectors, slippage manipulation paths, and access control risks that standard V3 audits never covered. If you're building on V4 — custom hooks, router integrations, or modified swap logic — your attack surface is meaningfully larger than it looks.
Get the DeFi Protocol Security Checklist
15 vulnerabilities every DeFi team should check before mainnet. Used by 30+ protocols.
No spam. Unsubscribe anytime.


