@@ -24,6 +24,7 @@ import { CCTPLib } from "./libraries/CCTPLib.sol";
2424import { CurveLib } from "./libraries/CurveLib.sol " ;
2525import { ERC4626Lib } from "./libraries/ERC4626Lib.sol " ;
2626import { IDaiUsdsLike, IPSMLike, PSMLib } from "./libraries/PSMLib.sol " ;
27+ import { UniswapV4Lib } from "./libraries/UniswapV4Lib.sol " ;
2728
2829import { OptionsBuilder } from "layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol " ;
2930
@@ -129,6 +130,12 @@ contract MainnetController is ReentrancyGuard, AccessControlEnumerable {
129130 bool isWhitelisted
130131 );
131132 event RelayerRemoved (address indexed relayer );
133+ event UniswapV4TickLimitsSet (
134+ bytes32 indexed poolId ,
135+ int24 tickLowerMin ,
136+ int24 tickUpperMax ,
137+ uint24 maxTickSpacing
138+ );
132139
133140 /**********************************************************************************************/
134141 /*** State variables ***/
@@ -153,6 +160,9 @@ contract MainnetController is ReentrancyGuard, AccessControlEnumerable {
153160 bytes32 public LIMIT_SPARK_VAULT_TAKE = keccak256 ("LIMIT_SPARK_VAULT_TAKE " );
154161 bytes32 public LIMIT_SUPERSTATE_SUBSCRIBE = keccak256 ("LIMIT_SUPERSTATE_SUBSCRIBE " );
155162 bytes32 public LIMIT_SUSDE_COOLDOWN = keccak256 ("LIMIT_SUSDE_COOLDOWN " );
163+ bytes32 public LIMIT_UNISWAP_V4_DEPOSIT = UniswapV4Lib.LIMIT_DEPOSIT;
164+ bytes32 public LIMIT_UNISWAP_V4_WITHDRAW = UniswapV4Lib.LIMIT_WITHDRAW;
165+ bytes32 public LIMIT_UNISWAP_V4_SWAP = UniswapV4Lib.LIMIT_SWAP;
156166 bytes32 public LIMIT_USDC_TO_CCTP = keccak256 ("LIMIT_USDC_TO_CCTP " );
157167 bytes32 public LIMIT_USDC_TO_DOMAIN = keccak256 ("LIMIT_USDC_TO_DOMAIN " );
158168 bytes32 public LIMIT_USDE_BURN = keccak256 ("LIMIT_USDE_BURN " );
@@ -194,6 +204,9 @@ contract MainnetController is ReentrancyGuard, AccessControlEnumerable {
194204 // ERC4626 exchange rate thresholds (1e36 precision)
195205 mapping (address token = > uint256 maxExchangeRate ) public maxExchangeRates;
196206
207+ // Uniswap V4 tick ranges
208+ mapping (bytes32 poolId = > UniswapV4Lib.TickLimits tickLimits ) public uniswapV4TickLimits;
209+
197210 /**********************************************************************************************/
198211 /*** Initialization ***/
199212 /**********************************************************************************************/
@@ -307,6 +320,31 @@ contract MainnetController is ReentrancyGuard, AccessControlEnumerable {
307320 );
308321 }
309322
323+ function setUniswapV4TickLimits (
324+ bytes32 poolId ,
325+ int24 tickLowerMin ,
326+ int24 tickUpperMax ,
327+ uint24 maxTickSpacing
328+ )
329+ external nonReentrant
330+ {
331+ _checkRole (DEFAULT_ADMIN_ROLE);
332+
333+ require (
334+ ((tickLowerMin == 0 ) && (tickUpperMax == 0 ) && (maxTickSpacing == 0 )) ||
335+ ((maxTickSpacing > 0 ) && (tickLowerMin < tickUpperMax)),
336+ "MC/invalid-ticks "
337+ );
338+
339+ uniswapV4TickLimits[poolId] = UniswapV4Lib.TickLimits ({
340+ tickLowerMin : tickLowerMin,
341+ tickUpperMax : tickUpperMax,
342+ maxTickSpacing : maxTickSpacing
343+ });
344+
345+ emit UniswapV4TickLimitsSet (poolId, tickLowerMin, tickUpperMax, maxTickSpacing);
346+ }
347+
310348 /**********************************************************************************************/
311349 /*** Freezer functions ***/
312350 /**********************************************************************************************/
@@ -598,6 +636,100 @@ contract MainnetController is ReentrancyGuard, AccessControlEnumerable {
598636 }));
599637 }
600638
639+ /**********************************************************************************************/
640+ /*** Uniswap V4 functions ***/
641+ /**********************************************************************************************/
642+
643+ function mintPositionUniswapV4 (
644+ bytes32 poolId ,
645+ int24 tickLower ,
646+ int24 tickUpper ,
647+ uint128 liquidity ,
648+ uint256 amount0Max ,
649+ uint256 amount1Max
650+ )
651+ external nonReentrant
652+ {
653+ _checkRole (RELAYER);
654+
655+ UniswapV4Lib.mintPosition ({
656+ proxy : address (proxy),
657+ rateLimits : address (rateLimits),
658+ poolId : poolId,
659+ tickLower : tickLower,
660+ tickUpper : tickUpper,
661+ liquidity : liquidity,
662+ amount0Max : amount0Max,
663+ amount1Max : amount1Max,
664+ tickLimits : uniswapV4TickLimits
665+ });
666+ }
667+
668+ function increaseLiquidityUniswapV4 (
669+ bytes32 poolId ,
670+ uint256 tokenId ,
671+ uint128 liquidityIncrease ,
672+ uint256 amount0Max ,
673+ uint256 amount1Max
674+ )
675+ external nonReentrant
676+ {
677+ _checkRole (RELAYER);
678+
679+ UniswapV4Lib.increasePosition ({
680+ proxy : address (proxy),
681+ rateLimits : address (rateLimits),
682+ poolId : poolId,
683+ tokenId : tokenId,
684+ liquidityIncrease : liquidityIncrease,
685+ amount0Max : amount0Max,
686+ amount1Max : amount1Max
687+ });
688+ }
689+
690+ function decreaseLiquidityUniswapV4 (
691+ bytes32 poolId ,
692+ uint256 tokenId ,
693+ uint128 liquidityDecrease ,
694+ uint256 amount0Min ,
695+ uint256 amount1Min
696+ )
697+ external nonReentrant
698+ {
699+ _checkRole (RELAYER);
700+
701+ UniswapV4Lib.decreasePosition ({
702+ proxy : address (proxy),
703+ rateLimits : address (rateLimits),
704+ poolId : poolId,
705+ tokenId : tokenId,
706+ liquidityDecrease : liquidityDecrease,
707+ amount0Min : amount0Min,
708+ amount1Min : amount1Min
709+ });
710+ }
711+
712+ function swapUniswapV4 (
713+ bytes32 poolId ,
714+ address tokenIn ,
715+ uint128 amountIn ,
716+ uint128 amountOutMin
717+ )
718+ external nonReentrant
719+ {
720+ _checkRole (RELAYER);
721+
722+ UniswapV4Lib.swap ({
723+ proxy : address (proxy),
724+ rateLimits : address (rateLimits),
725+ poolId : poolId,
726+ tokenIn : tokenIn,
727+ amountIn : amountIn,
728+ amountOutMin : amountOutMin,
729+ maxSlippage : maxSlippages[address (uint160 (uint256 (poolId)))]
730+ });
731+ }
732+
601733 /**********************************************************************************************/
602734 /*** Relayer Ethena functions ***/
603735 /**********************************************************************************************/
@@ -813,7 +945,7 @@ contract MainnetController is ReentrancyGuard, AccessControlEnumerable {
813945 });
814946
815947 // Query the min amount received on the destination chain and set it.
816- ( ,, OFTReceipt memory receipt ) = ILayerZero (oftAddress).quoteOFT (sendParams);
948+ ( , , OFTReceipt memory receipt ) = ILayerZero (oftAddress).quoteOFT (sendParams);
817949 sendParams.minAmountLD = receipt.amountReceivedLD;
818950
819951 MessagingFee memory fee = ILayerZero (oftAddress).quoteSend (sendParams, false );
0 commit comments