Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,9 @@
path = lib/xchain-helpers
url = https://github.com/grove-labs/xchain-helpers
branch = master
[submodule "lib/uniswap-v4-periphery"]
path = lib/uniswap-v4-periphery
url = https://github.com/Uniswap/v4-periphery
[submodule "lib/uniswap-v4-core"]
path = lib/uniswap-v4-core
url = https://github.com/Uniswap/v4-core
11 changes: 10 additions & 1 deletion foundry.lock
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@
"lib/spark-psm": {
"rev": "6a5a579cb503a461df254007064370f732fcd19d"
},
"lib/uniswap-v4-core": {
"tag": {
"name": "v4.0.0",
"rev": "e50237c43811bd9b526eff40f26772152a42daba"
}
},
"lib/uniswap-v4-periphery": {
"rev": "3779387e5d296f39df543d23524b050f89a62917"
},
"lib/usds": {
"rev": "1e91268374d2796abcbb1af2b75473b2af488265"
},
Expand All @@ -50,4 +59,4 @@
"rev": "53f6ced11ae4828e7bd55ba7a6a713c97f2b19c4"
}
}
}
}
3 changes: 2 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ remappings = [
'@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/',
'@layerzerolabs/lz-evm-messagelib-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/messagelib/',
'solidity-bytes-utils/=lib/solidity-bytes-utils/',
'forge-std/=lib/forge-std/src/'
'forge-std/=lib/forge-std/src/',
'@uniswap/v4-core/=lib/uniswap-v4-core/'
]
# all files should explicitly opt-into this
no_match_coverage = 'src/libraries/uniswap-v3/UniV3OracleLib.sol|src/libraries/uniswap-v3/UniV3UtilsLib.sol'
Expand Down
1 change: 1 addition & 0 deletions lib/uniswap-v4-core
Submodule uniswap-v4-core added at d153b0
1 change: 1 addition & 0 deletions lib/uniswap-v4-periphery
Submodule uniswap-v4-periphery added at 377938
131 changes: 131 additions & 0 deletions src/MainnetController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import { IDaiUsdsLike, IPSMLike, PSMLib } from "./libraries/PSMLib.sol";
import { PendleLib } from "./libraries/PendleLib.sol";
import { ERC20Lib } from "./libraries/common/ERC20Lib.sol";
import { UniswapV3Lib } from "./libraries/UniswapV3Lib.sol";
import { UniswapV4Lib } from "./libraries/UniswapV4Lib.sol";


import { OptionsBuilder } from "layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol";

Expand Down Expand Up @@ -73,6 +75,12 @@ contract MainnetController is AccessControl {
event UniswapV3PoolLowerTickUpdated(address indexed pool, int24 lowerTick);
event UniswapV3PoolUpperTickUpdated(address indexed pool, int24 upperTick);
event UniswapV3PoolTwapSecondsAgoUpdated(address indexed pool, uint32 twapSecondsAgo);
event UniswapV4TickLimitsSet(
bytes32 indexed poolId,
int24 tickLowerMin,
int24 tickUpperMax,
uint24 maxTickSpacing
);

/**********************************************************************************************/
/*** State variables ***/
Expand Down Expand Up @@ -144,6 +152,9 @@ contract MainnetController is AccessControl {
// ERC4626 exchange rate thresholds (1e36 precision)
mapping(address token => uint256 maxExchangeRate) public maxExchangeRates;

// Uniswap V4 tick ranges
mapping(bytes32 poolId => UniswapV4Lib.TickLimits tickLimits) public uniswapV4TickLimits;

/**********************************************************************************************/
/*** Initialization ***/
/**********************************************************************************************/
Expand Down Expand Up @@ -266,6 +277,31 @@ contract MainnetController is AccessControl {
);
}

function setUniswapV4TickLimits(
bytes32 poolId,
int24 tickLowerMin,
int24 tickUpperMax,
uint24 maxTickSpacing
)
external
{
_checkRole(DEFAULT_ADMIN_ROLE);

require(
((tickLowerMin == 0) && (tickUpperMax == 0) && (maxTickSpacing == 0)) ||
((maxTickSpacing > 0) && (tickLowerMin < tickUpperMax)),
"MC/invalid-ticks"
);

uniswapV4TickLimits[poolId] = UniswapV4Lib.TickLimits({
tickLowerMin : tickLowerMin,
tickUpperMax : tickUpperMax,
maxTickSpacing : maxTickSpacing
});

emit UniswapV4TickLimitsSet(poolId, tickLowerMin, tickUpperMax, maxTickSpacing);
}

/**********************************************************************************************/
/*** Freezer functions ***/
/**********************************************************************************************/
Expand Down Expand Up @@ -725,6 +761,101 @@ contract MainnetController is AccessControl {
);
}

/**********************************************************************************************/
/*** Uniswap V4 functions ***/
/**********************************************************************************************/

function mintPositionUniswapV4(
bytes32 poolId,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 amount0Max,
uint256 amount1Max
)
external
{
_checkRole(RELAYER);

UniswapV4Lib.mintPosition({
proxy : address(proxy),
rateLimits : address(rateLimits),
poolId : poolId,
tickLower : tickLower,
tickUpper : tickUpper,
liquidity : liquidity,
amount0Max : amount0Max,
amount1Max : amount1Max,
tickLimits : uniswapV4TickLimits
});
}

function increaseLiquidityUniswapV4(
bytes32 poolId,
uint256 tokenId,
uint128 liquidityIncrease,
uint256 amount0Max,
uint256 amount1Max
)
external
{
_checkRole(RELAYER);

UniswapV4Lib.increasePosition({
proxy : address(proxy),
rateLimits : address(rateLimits),
poolId : poolId,
tokenId : tokenId,
liquidityIncrease : liquidityIncrease,
amount0Max : amount0Max,
amount1Max : amount1Max,
tickLimits : uniswapV4TickLimits
});
}

function decreaseLiquidityUniswapV4(
bytes32 poolId,
uint256 tokenId,
uint128 liquidityDecrease,
uint256 amount0Min,
uint256 amount1Min
)
external
{
_checkRole(RELAYER);

UniswapV4Lib.decreasePosition({
proxy : address(proxy),
rateLimits : address(rateLimits),
poolId : poolId,
tokenId : tokenId,
liquidityDecrease : liquidityDecrease,
amount0Min : amount0Min,
amount1Min : amount1Min
});
}

function swapUniswapV4(
bytes32 poolId,
address tokenIn,
uint128 amountIn,
uint128 amountOutMin
)
external
{
_checkRole(RELAYER);

UniswapV4Lib.swap({
proxy : address(proxy),
rateLimits : address(rateLimits),
poolId : poolId,
tokenIn : tokenIn,
amountIn : amountIn,
amountOutMin : amountOutMin,
maxSlippage : maxSlippages[address(uint160(uint256(poolId)))]
});
}


/**********************************************************************************************/
/*** Relayer Ethena functions ***/
Expand Down
4 changes: 4 additions & 0 deletions src/RateLimitHelpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ library RateLimitHelpers {
return keccak256(abi.encode(key, domain));
}

function makeBytes32Key(bytes32 key, bytes32 a) internal pure returns (bytes32) {
return keccak256(abi.encode(key, a));
}

}
18 changes: 18 additions & 0 deletions src/interfaces/Common.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;

interface IERC20Like {

function approve(address spender, uint256 amount) external returns (bool success);

function balanceOf(address account) external view returns (uint256 balance);

function decimals() external view returns (uint8 decimals);

}

interface IPermit2Like {

function approve(address token, address spender, uint160 amount, uint48 expiration) external;

}
27 changes: 27 additions & 0 deletions src/interfaces/UniswapV4Interfaces.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;

import { PoolId } from "../../lib/uniswap-v4-core/src/types/PoolId.sol";
import { PoolKey } from "../../lib/uniswap-v4-core/src/types/PoolKey.sol";

import { PositionInfo } from "../../lib/uniswap-v4-periphery/src/libraries/PositionInfoLibrary.sol";

interface IPositionManagerLike {

function modifyLiquidities(bytes calldata unlockData, uint256 deadline) external payable;

function getPoolAndPositionInfo(
uint256 tokenId
) external view returns (PoolKey memory poolKey, PositionInfo info);

function poolKeys(bytes25 poolId) external view returns (PoolKey memory poolKey);

function ownerOf(uint256 tokenId) external view returns (address owner);

}

interface IUniversalRouterLike {

function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external;

}
Loading
Loading