Skip to content

Commit

Permalink
feat: PT markets Dec maturity
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeNervoXS committed Jun 10, 2024
1 parent 0de98f5 commit 927a3da
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.17;

import "borrow-staked/swapper/LevSwapper/morpho/PendleLevSwapperMorpho.sol";

/// @author Angle Labs, Inc.
/// @notice PT weETH leverage swapper with maturity Dec 24
contract PendleLevSwapperMorphoWeETHDec24 is PendleLevSwapperMorpho {
constructor(
ICoreBorrow _core,
IUniswapV3Router _uniV3Router,
address _aggregator,
IAngleRouterSidechain _angleRouter,
IMorphoBase _morpho
) PendleLevSwapperMorpho(_core, _uniV3Router, _aggregator, _angleRouter, _morpho) {}

/// @inheritdoc BaseLevSwapper
function angleStaker() public pure override returns (IBorrowStaker) {
return IBorrowStaker(address(0));
}

/// @inheritdoc PendleLevSwapperMorpho
function PT() public pure override returns (IERC20) {
return IERC20(0x6ee2b5E19ECBa773a352E5B21415Dc419A700d1d);
}

/// @inheritdoc PendleLevSwapperMorpho
function SY() public pure override returns (IStandardizedYield) {
return IStandardizedYield(0xAC0047886a985071476a1186bE89222659970d65);
}

/// @inheritdoc PendleLevSwapperMorpho
function YT() public pure override returns (IPYieldTokenV2) {
return IPYieldTokenV2(0x129e6B5DBC0Ecc12F9e486C5BC9cDF1a6A80bc6A);
}

/// @inheritdoc PendleLevSwapperMorpho
function market() public pure override returns (IPMarketV3) {
return IPMarketV3(0x7d372819240D14fB477f17b964f95F33BeB4c704);
}

/// @inheritdoc PendleLevSwapperMorpho
function collateral() public pure override returns (IERC20) {
return IERC20(0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee);
}
}
1 change: 1 addition & 0 deletions scripts/foundry/mainnet/MainnetConstants.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ contract MainnetConstants {
address constant USDA = 0x0000206329b97DB379d5E1Bf586BbDB969C63274;
address constant EZETH = 0xbf5495Efe5DB9ce00f80364C8B423567e58d2110;
address constant PTWeETH = 0xc69Ad9baB1dEE23F4605a82b3354F8E40d1E5966;
address constant PTWeETHDec24 = 0x6ee2b5E19ECBa773a352E5B21415Dc419A700d1d;
address constant PTUSDe = 0xa0021EF8970104c2d008F38D92f115ad56a9B8e1;
address constant RSETH = 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7;
address constant GTETHPRIME = 0x2371e134e3455e0593363cBF89d3b6cf53740618;
Expand Down
7 changes: 4 additions & 3 deletions scripts/foundry/mainnet/morpho/MorphoDeployMarket.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { StdCheats, StdAssertions } from "forge-std/Test.sol";
import "borrow/interfaces/ICoreBorrow.sol";
import "borrow/interfaces/IAngleRouterSidechain.sol";
import "borrow/interfaces/external/uniswap/IUniswapRouter.sol";
import { SwapType, BaseLevSwapper, PendleLevSwapperMorphoWeETH, PendleLevSwapperMorpho, Swapper } from "borrow-staked/swapper/LevSwapper/morpho/implementations/PendleLevSwapperMorphoWeETH.sol";
import { SwapType, BaseLevSwapper, PendleLevSwapperMorpho, Swapper } from "borrow-staked/swapper/LevSwapper/morpho/implementations/PendleLevSwapperMorphoWeETH.sol";
import "../MainnetConstants.s.sol";
import { MarketParams } from "morpho-blue/libraries/MarketParamsLib.sol";
import { IIrm } from "morpho-blue/interfaces/IIRM.sol";
Expand All @@ -16,6 +16,7 @@ import { IOracle as IMorphoOracle } from "morpho-blue/interfaces/IOracle.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { MorphoFeedPTweETH } from "borrow/oracle/morpho/mainnet/MorphoFeedPTweETH.sol";
import { MorphoFeedPTweETHDec24 } from "borrow/oracle/morpho/mainnet/MorphoFeedPTweETHDec24.sol";
import { IAccessControlManager } from "borrow/interfaces/IAccessControlManager.sol";
import "borrow-staked/mock/MockCoreBorrow.sol";
import "borrow-staked/interfaces/external/morpho/IMorphoChainlinkOracleV2Factory.sol";
Expand Down Expand Up @@ -44,7 +45,7 @@ contract MorphoDeployMarket is Script, MainnetConstants, StdCheats, StdAssertion

// PT weETH market
address priceFeed = address(
new MorphoFeedPTweETH(IAccessControlManager(address(coreBorrow)), _MAX_IMPLIED_RATE, _TWAP_DURATION)
new MorphoFeedPTweETHDec24(IAccessControlManager(address(coreBorrow)), _MAX_IMPLIED_RATE, _TWAP_DURATION)
);
oracle = IMorphoChainlinkOracleV2Factory(MORPHO_ORACLE_FACTORY).createMorphoChainlinkOracleV2(
address(0),
Expand Down Expand Up @@ -77,7 +78,7 @@ contract MorphoDeployMarket is Script, MainnetConstants, StdCheats, StdAssertion

uint256 price = IMorphoOracle(oracle).price();
assertApproxEqRel(price, 3350 * 10 ** 36, 100 ** 36);
params.collateralToken = PTWeETH;
params.collateralToken = PTWeETHDec24;
params.lltv = LLTV_86;
params.irm = IRM_MODEL;
params.oracle = oracle;
Expand Down
2 changes: 1 addition & 1 deletion scripts/foundry/mainnet/morpho/MorphoInteractMarket.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { console } from "forge-std/console.sol";
import { StdCheats, StdAssertions } from "forge-std/Test.sol";
import "borrow/interfaces/IAngleRouterSidechain.sol";
import "borrow/interfaces/external/uniswap/IUniswapRouter.sol";
import { SwapType, BaseLevSwapper, PendleLevSwapperMorphoWeETH, PendleLevSwapperMorpho, Swapper } from "borrow-staked/swapper/LevSwapper/morpho/implementations/PendleLevSwapperMorphoWeETH.sol";
import { SwapType, BaseLevSwapper, PendleLevSwapperMorpho, Swapper } from "borrow-staked/swapper/LevSwapper/morpho/implementations/PendleLevSwapperMorphoWeETH.sol";
import { MarketParams } from "morpho-blue/libraries/MarketParamsLib.sol";
import { IIrm } from "morpho-blue/interfaces/IIRM.sol";
import { IMorpho, Position } from "morpho-blue/interfaces/IMorpho.sol";
Expand Down
4 changes: 2 additions & 2 deletions scripts/foundry/mainnet/morpho/SwapperLevMorphoPTWeETH.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { StdCheats, StdAssertions } from "forge-std/Test.sol";
import "borrow/interfaces/ICoreBorrow.sol";
import "borrow/interfaces/IAngleRouterSidechain.sol";
import "borrow/interfaces/external/uniswap/IUniswapRouter.sol";
import { PendleLevSwapperMorphoWeETH } from "borrow-staked/swapper/LevSwapper/morpho/implementations/PendleLevSwapperMorphoWeETH.sol";
import { PendleLevSwapperMorphoWeETHDec24 } from "borrow-staked/swapper/LevSwapper/morpho/implementations/PendleLevSwapperMorphoWeETHDec24.sol";
import "../MainnetConstants.s.sol";
import { IMorpho } from "morpho-blue/interfaces/IMorpho.sol";
import "borrow-staked/mock/MockCoreBorrow.sol";
Expand All @@ -25,7 +25,7 @@ contract SwapperLevMorphoPTWeETH is Script, MainnetConstants, StdCheats, StdAsse
// coreBorrow = new MockCoreBorrow();
// coreBorrow.toggleGuardian(deployer);

PendleLevSwapperMorphoWeETH swapperMorphoPTWeETH = new PendleLevSwapperMorphoWeETH(
PendleLevSwapperMorphoWeETHDec24 swapperMorphoPTWeETH = new PendleLevSwapperMorphoWeETHDec24(
ICoreBorrow(coreBorrow),
IUniswapV3Router(UNI_V3_ROUTER),
ONE_INCH,
Expand Down
182 changes: 182 additions & 0 deletions test/foundry/swapper/morpho/PendleLevSwapperMorphoWeETHDec24Test.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

import "../../BaseTest.test.sol";
import "borrow-staked/interfaces/IBorrowStaker.sol";
import "borrow/interfaces/ICoreBorrow.sol";
import "borrow-staked/mock/MockTokenPermit.sol";
import { SwapType, BaseLevSwapper, PendleLevSwapperMorphoWeETHDec24, PendleLevSwapperMorpho, Swapper, IUniswapV3Router, IAngleRouterSidechain } from "borrow-staked/swapper/LevSwapper/morpho/implementations/PendleLevSwapperMorphoWeETHDec24.sol";
import { IMorphoBase } from "morpho-blue/interfaces/IMorpho.sol";

contract PendleLevSwapperMorphoWeETHDec24Test is BaseTest {
using stdStorage for StdStorage;
using SafeERC20 for IERC20;

address internal constant _ONE_INCH = 0x111111125421cA6dc452d289314280a0f8842A65;
IUniswapV3Router internal constant _UNI_V3_ROUTER = IUniswapV3Router(0xE592427A0AEce92De3Edee1F18E0157C05861564);
IAngleRouterSidechain internal constant _ANGLE_ROUTER =
IAngleRouterSidechain(address(uint160(uint256(keccak256(abi.encodePacked("_fakeAngleRouter"))))));

uint256 internal constant _BPS = 10000;
IERC20 constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IMorphoBase constant MORPHO = IMorphoBase(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb);
PendleLevSwapperMorpho public swapper;
IERC20 public asset;
IERC20 public collateral;

uint256 public constant DEPOSIT_LENGTH = 10;
uint256 public constant WITHDRAW_LENGTH = 10;

function setUp() public override {
super.setUp();

_ethereum = vm.createFork(vm.envString("ETH_NODE_URI_MAINNET"), 20062045);
vm.selectFork(_ethereum);

// reset coreBorrow because the `makePersistent()` doens't work on my end
coreBorrow = new MockCoreBorrow();
coreBorrow.toggleGuardian(_GUARDIAN);
coreBorrow.toggleGovernor(_GOVERNOR);

swapper = new PendleLevSwapperMorphoWeETHDec24(coreBorrow, _UNI_V3_ROUTER, _ONE_INCH, _ANGLE_ROUTER, MORPHO);
asset = swapper.PT();
collateral = swapper.collateral();

vm.startPrank(_alice);
asset.approve(address(swapper), type(uint256).max);
collateral.approve(address(swapper), type(uint256).max);
vm.stopPrank();
}

function test_Leverage_NoSwap_Success(uint256 amount) public {
amount = bound(amount, 10 ** 15, 10 ** 20);
deal(address(collateral), address(_alice), amount);

vm.startPrank(_alice);

// intermediary variables
bytes[] memory oneInchData = new bytes[](0);

uint256 minAmountOut = amount / 2;
bytes memory addData;
bytes memory swapData = abi.encode(oneInchData, addData);
bytes memory leverageData = abi.encode(true, _alice, swapData);
bytes memory data = abi.encode(address(0), 0, SwapType.Leverage, leverageData);

// we first need to send the tokens before hand, you should always use the swapper
// in another tx to not loose your funds by front running
collateral.transfer(address(swapper), amount);
swapper.swap(IERC20(address(collateral)), IERC20(address(asset)), _alice, 0, amount, data);

vm.stopPrank();

assertEq(collateral.balanceOf(_alice), 0);
assertEq(collateral.balanceOf(address(swapper)), 0);
assertEq(asset.balanceOf(address(swapper)), 0);
assertGe(asset.balanceOf(_alice), minAmountOut);
}

function test_Deleverage_NoSwap_Success(uint256 amount) public {
amount = bound(amount, 10 ** 15, 10 ** 20);
deal(address(asset), address(_alice), amount);

vm.startPrank(_alice);

// intermediary variables
bytes[] memory oneInchData = new bytes[](0);

uint256 minAmountOut = amount / 2;
IERC20[] memory sweepTokens = new IERC20[](0);
bytes memory removeData = abi.encode(uint256(minAmountOut));
bytes memory swapData = abi.encode(0, amount, sweepTokens, oneInchData, removeData);
bytes memory leverageData = abi.encode(false, _alice, swapData);
bytes memory data = abi.encode(address(0), 0, SwapType.Leverage, leverageData);

// we first need to send the tokens before hand, you should always use the swapper
// in another tx to not loose your funds by front running
asset.transfer(address(swapper), amount);
swapper.swap(IERC20(address(asset)), IERC20(address(collateral)), _alice, 0, amount, data);

vm.stopPrank();

assertGe(collateral.balanceOf(_alice), minAmountOut);
assertEq(collateral.balanceOf(address(swapper)), 0);
assertEq(asset.balanceOf(address(swapper)), 0);
assertEq(asset.balanceOf(_alice), 0);
}

function test_Leverage_Swap_Success() public {
uint256 amount = 10 ether;
deal(address(WETH), address(_alice), amount);

vm.startPrank(_alice);

// intermediary variables
bytes[] memory oneInchData = new bytes[](1);
// swap WETH for ezETH
oneInchData[0] = abi.encode(
address(WETH),
0,
hex"83800a8e000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000084d9cc8e30fec9cd2880000000000000000000007a415b19932c0105c82fdb6b720bb01b0cc2cae3a20a9a94"
);

uint256 minAmountOut = amount / 2;
bytes memory addData;
bytes memory swapData = abi.encode(oneInchData, addData);
bytes memory leverageData = abi.encode(true, _alice, swapData);
bytes memory data = abi.encode(address(0), 0, SwapType.Leverage, leverageData);

// we first need to send the tokens before hand, you should always use the swapper
// in another tx to not loose your funds by front running
WETH.transfer(address(swapper), amount);
swapper.swap(IERC20(address(WETH)), IERC20(address(asset)), _alice, 0, amount, data);

vm.stopPrank();

assertEq(WETH.balanceOf(_alice), 0);
assertEq(WETH.balanceOf(address(swapper)), 0);
assertEq(collateral.balanceOf(_alice), 0);
assertEq(collateral.balanceOf(address(swapper)), 0);
assertEq(asset.balanceOf(address(swapper)), 0);
assertGe(asset.balanceOf(_alice), minAmountOut);
}

function test_Deleverage_Swap_Success() public {
uint256 eps = 2 ether;
uint256 amount = 10 ether;
deal(address(asset), address(_alice), amount + eps);

vm.startPrank(_alice);

// intermediary variables
bytes[] memory oneInchData = new bytes[](1);
// swap weETH for WETH
oneInchData[0] = abi.encode(
address(collateral),
0,
hex"83800a8e000000000000000000000000cd5fe23c85820f7b72d0926fc9b05b43e359b7ee0000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000008df12dbf0ec541092800000000000000000000007a415b19932c0105c82fdb6b720bb01b0cc2cae3a20a9a94"
);

uint256 minAmountOut = amount / 2;
IERC20[] memory sweepTokens = new IERC20[](1);
sweepTokens[0] = collateral;
bytes memory removeData = abi.encode(uint256(minAmountOut));
bytes memory swapData = abi.encode(0, amount + eps, sweepTokens, oneInchData, removeData);
bytes memory leverageData = abi.encode(false, _alice, swapData);
bytes memory data = abi.encode(address(0), 0, SwapType.Leverage, leverageData);

// we first need to send the tokens before hand, you should always use the swapper
// in another tx to not loose your funds by front running
asset.transfer(address(swapper), amount + eps);
swapper.swap(IERC20(address(asset)), IERC20(address(WETH)), _alice, 0, amount, data);

vm.stopPrank();

assertGe(WETH.balanceOf(_alice), (amount * 99) / 100);
assertEq(WETH.balanceOf(address(swapper)), 0);
assertGt(collateral.balanceOf(_alice), 0);
assertEq(collateral.balanceOf(address(swapper)), 0);
assertEq(asset.balanceOf(address(swapper)), 0);
assertEq(asset.balanceOf(_alice), 0);
}
}

0 comments on commit 927a3da

Please sign in to comment.