@@ -15,6 +15,7 @@ import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
1515import {BaseHook} from "../../utils/BaseHook.sol " ;
1616import {V2OnV4PairDeployer} from "./V2OnV4PairDeployer.sol " ;
1717import {UQ112x112} from "./UQ112x112.sol " ;
18+ import {IV2OnV4Pair} from "../../interfaces/IV2OnV4Pair.sol " ;
1819
1920enum UnlockCallbackAction {
2021 MINT,
@@ -32,7 +33,7 @@ struct UnlockCallback {
3233/// @author Uniswap Labs
3334/// @notice A V2-style AMM pair contract that operates on Uniswap V4 infrastructure
3435/// @dev Implements constant product (x*y=k) AMM logic while leveraging V4's singleton pool manager
35- contract V2OnV4Pair is ERC20 , ReentrancyGuardTransient {
36+ contract V2OnV4Pair is IV2OnV4Pair , ERC20 , ReentrancyGuardTransient {
3637 using UQ112x112 for uint224 ;
3738 using SafeTransferLib for ERC20 ;
3839 using CurrencyLibrary for Currency;
@@ -79,29 +80,6 @@ contract V2OnV4Pair is ERC20, ReentrancyGuardTransient {
7980 _;
8081 }
8182
82- error K ();
83- error Forbidden ();
84- error NotPoolManager ();
85- error InvalidUnlockCallbackData ();
86- error InsufficientLiquidityBurned ();
87- error InsufficientLiquidityMinted ();
88- error InsufficientOutputAmount ();
89- error InsufficientInputAmount ();
90- error InsufficientLiquidity ();
91- error InvalidTo ();
92-
93- event Mint (address indexed sender , uint256 amount0 , uint256 amount1 );
94- event Burn (address indexed sender , uint256 amount0 , uint256 amount1 , address indexed to );
95- event Swap (
96- address indexed sender ,
97- uint256 amount0In ,
98- uint256 amount1In ,
99- uint256 amount0Out ,
100- uint256 amount1Out ,
101- address indexed to
102- );
103- event Sync (uint112 reserve0 , uint112 reserve1 );
104-
10583 /// @notice Deploys a new V2 pair on V4
10684 /// @dev Called by the factory with deployment parameters
10785 constructor () ERC20 ("Uniswap V2 " , "UNI-V2 " , 18 ) {
@@ -118,8 +96,13 @@ contract V2OnV4Pair is ERC20, ReentrancyGuardTransient {
11896 /// @dev Low-level function that should be called through a router with proper safety checks
11997 /// @param to Address to receive the minted LP tokens
12098 /// @return liquidity Amount of LP tokens minted
121- function mint (address to ) external nonReentrant returns (uint256 liquidity ) {
122- poolManager.unlock (abi.encode (UnlockCallback ({action: UnlockCallbackAction.MINT, to: to, data: new bytes (0 )})));
99+ function mint (address to ) external override nonReentrant returns (uint256 liquidity ) {
100+ (liquidity) = abi.decode (
101+ poolManager.unlock (
102+ abi.encode (UnlockCallback ({action: UnlockCallbackAction.MINT, to: to, data: new bytes (0 )}))
103+ ),
104+ (uint256 )
105+ );
123106 }
124107
125108 /// @notice Internal mint function that handles ERC20 token deposits and liquidity creation
@@ -128,18 +111,23 @@ contract V2OnV4Pair is ERC20, ReentrancyGuardTransient {
128111 /// @return liquidity Amount of LP tokens minted
129112 function _mint (address to ) internal returns (uint256 liquidity ) {
130113 // transform ERC20 tokens into claims
131- ( uint256 amount0 , uint256 amount1 ) = _slurp ();
114+ _slurp ();
132115 // Then mint liquidity as normal with those claims
133- _mintClaims (to);
116+ liquidity = _mintClaims (to);
134117 }
135118
136119 /// @notice Burns liquidity tokens and returns underlying assets
137120 /// @dev Low-level function that should be called through a router with proper safety checks
138121 /// @param to Address to receive the underlying tokens
139122 /// @return amount0 Amount of token0 returned
140123 /// @return amount1 Amount of token1 returned
141- function burn (address to ) external nonReentrant returns (uint256 amount0 , uint256 amount1 ) {
142- poolManager.unlock (abi.encode (UnlockCallback ({action: UnlockCallbackAction.BURN, to: to, data: new bytes (0 )})));
124+ function burn (address to ) external override nonReentrant returns (uint256 amount0 , uint256 amount1 ) {
125+ (amount0, amount1) = abi.decode (
126+ poolManager.unlock (
127+ abi.encode (UnlockCallback ({action: UnlockCallbackAction.BURN, to: to, data: new bytes (0 )}))
128+ ),
129+ (uint256 , uint256 )
130+ );
143131 }
144132
145133 /// @notice Internal burn function that redeems LP tokens for underlying assets
@@ -158,7 +146,11 @@ contract V2OnV4Pair is ERC20, ReentrancyGuardTransient {
158146 /// @param amount1Out Amount of token1 to send
159147 /// @param to Address to receive output tokens
160148 /// @param data Callback data for flash swaps
161- function swap (uint256 amount0Out , uint256 amount1Out , address to , bytes calldata data ) external nonReentrant {
149+ function swap (uint256 amount0Out , uint256 amount1Out , address to , bytes calldata data )
150+ external
151+ override
152+ nonReentrant
153+ {
162154 poolManager.unlock (
163155 abi.encode (
164156 UnlockCallback ({
@@ -207,7 +199,7 @@ contract V2OnV4Pair is ERC20, ReentrancyGuardTransient {
207199 /// @param to Address to receive the minted LP tokens
208200 /// @return liquidity Amount of LP tokens minted
209201 function mintClaims (address to ) external nonReentrant returns (uint256 liquidity ) {
210- _mintClaims (to);
202+ return _mintClaims (to);
211203 }
212204
213205 /// @notice Burns liquidity and returns claims directly
@@ -216,7 +208,7 @@ contract V2OnV4Pair is ERC20, ReentrancyGuardTransient {
216208 /// @return amount0 Amount of token0 claims returned
217209 /// @return amount1 Amount of token1 claims returned
218210 function burnClaims (address to ) external nonReentrant returns (uint256 amount0 , uint256 amount1 ) {
219- _burnClaims (to, true );
211+ return _burnClaims (to, true );
220212 }
221213
222214 /// @notice Executes a swap using V4 claims directly
@@ -239,13 +231,15 @@ contract V2OnV4Pair is ERC20, ReentrancyGuardTransient {
239231 function unlockCallback (bytes calldata data ) external onlyPoolManager returns (bytes memory ) {
240232 UnlockCallback memory callbackData = abi.decode (data, (UnlockCallback));
241233 if (callbackData.action == UnlockCallbackAction.MINT) {
242- _mint (callbackData.to);
234+ return abi.encode ( _mint (callbackData.to) );
243235 } else if (callbackData.action == UnlockCallbackAction.BURN) {
244- _burn (callbackData.to);
236+ (uint256 amount0 , uint256 amount1 ) = _burn (callbackData.to);
237+ return abi.encode (amount0, amount1);
245238 } else if (callbackData.action == UnlockCallbackAction.SWAP) {
246239 (uint256 amount0Out , uint256 amount1Out , bytes memory swapData ) =
247240 abi.decode (callbackData.data, (uint256 , uint256 , bytes ));
248241 _swap (amount0Out, amount1Out, callbackData.to, swapData);
242+ return new bytes (0 ); // no return data needed for swap
249243 } else {
250244 revert InvalidUnlockCallbackData ();
251245 }
0 commit comments