From 50f04554ef2e851bdba5700631d444113416fec0 Mon Sep 17 00:00:00 2001 From: Pranav Bhardwaj Date: Wed, 5 Jun 2024 23:16:30 -0400 Subject: [PATCH 1/2] add inflation factor to pendle market data --- contracts/exchangeIssuance/FlashMintHyETH.sol | 22 ++++++++++++++++--- .../ethereum/flashMintHyETH.spec.ts | 3 +++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/contracts/exchangeIssuance/FlashMintHyETH.sol b/contracts/exchangeIssuance/FlashMintHyETH.sol index 8d5366f0..82bb1250 100644 --- a/contracts/exchangeIssuance/FlashMintHyETH.sol +++ b/contracts/exchangeIssuance/FlashMintHyETH.sol @@ -51,6 +51,7 @@ contract FlashMintHyETH is Ownable, ReentrancyGuard { IPendlePrincipalToken pt; IPendleStandardizedYield sy; address underlying; + uint256 exchangeRateFactor; } /* ============ Constants ============= */ @@ -314,15 +315,22 @@ contract FlashMintHyETH is Ownable, ReentrancyGuard { * @param _sy Address of the corresponding Standardized Yield Token * @param _underlying Address of the underlying token to redeem to * @param _market Address of the Pendle Market to use for swapping between pt and sy + * @param _exchangeRateFactor Factor to multiply the exchange rate when supplying to Pendle Market */ function setPendleMarket( IPendlePrincipalToken _pt, IPendleStandardizedYield _sy, address _underlying, - IPendleMarketV3 _market + IPendleMarketV3 _market, + uint256 _exchangeRateFactor ) external onlyOwner { pendleMarkets[_pt] = _market; - pendleMarketData[_market] = PendleMarketData({ pt: _pt, sy: _sy, underlying: _underlying }); + pendleMarketData[_market] = PendleMarketData({ + pt: _pt, + sy: _sy, + underlying: _underlying, + exchangeRateFactor: _exchangeRateFactor + }); } /** @@ -340,7 +348,15 @@ contract FlashMintHyETH is Ownable, ReentrancyGuard { marketData.pt.transfer(msg.sender, ptAmount); } else if (_syToAccount < 0) { uint256 syAmount = uint256(-_syToAccount); - uint256 ethAmount = syAmount.mul(marketData.sy.exchangeRate()).div(1e18); + + // Withdraw necessary ETH, if deposit size is enough to move the oracle, then the exchange rate will not be + // valid for computing the amount of ETH to withdraw, so increase by exchangeRateFactor + uint256 ethAmount = syAmount.mul(marketData.sy.exchangeRate()).div(1 ether); + uint256 syAmountPreview = marketData.sy.previewDeposit(address(0), ethAmount); + if (syAmountPreview < syAmount) { + ethAmount = ethAmount * marketData.exchangeRateFactor / 1 ether; + } + marketData.sy.deposit{ value: ethAmount }(msg.sender, address(0), ethAmount, 0); } else { revert("Invalid callback"); diff --git a/test/integration/ethereum/flashMintHyETH.spec.ts b/test/integration/ethereum/flashMintHyETH.spec.ts index 04eab339..2ca610db 100644 --- a/test/integration/ethereum/flashMintHyETH.spec.ts +++ b/test/integration/ethereum/flashMintHyETH.spec.ts @@ -228,6 +228,7 @@ if (process.env.INTEGRATIONTEST) { eEthSyToken, addresses.tokens.weEth, addresses.dexes.pendle.markets.eEth0624, + ethers.utils.parseEther("1.0005"), ); // weETH -> weth pool: https://etherscan.io/address/0x7a415b19932c0105c82fdb6b720bb01b0cc2cae3 await flashMintHyETH.setSwapData(addresses.tokens.weEth, ADDRESS_ZERO, { @@ -253,6 +254,7 @@ if (process.env.INTEGRATIONTEST) { rsEthSyToken, addresses.tokens.rsEth, addresses.dexes.pendle.markets.rsEth0624, + ethers.utils.parseEther("1.0005"), ); // rsEth -> weth pool: https://etherscan.io/address/0x059615ebf32c946aaab3d44491f78e4f8e97e1d3 await flashMintHyETH.setSwapData(addresses.tokens.rsEth, ADDRESS_ZERO, { @@ -278,6 +280,7 @@ if (process.env.INTEGRATIONTEST) { rswEthSyToken, addresses.tokens.rswEth, addresses.dexes.pendle.markets.rswEth0624, + ethers.utils.parseEther("1.0005"), ); // rswEth -> weth pool: https://etherscan.io/address/0xe62627326d7794e20bb7261b24985294de1579fe await flashMintHyETH.setSwapData(addresses.tokens.rswEth, ADDRESS_ZERO, { From 6f067dca19ae5993b88203cc0afe927e547f2724 Mon Sep 17 00:00:00 2001 From: Pranav Bhardwaj Date: Wed, 5 Jun 2024 23:49:37 -0400 Subject: [PATCH 2/2] update FlashMintHyETH integration tests --- test/integration/ethereum/addresses.ts | 7 ++ .../ethereum/flashMintHyETH.spec.ts | 90 +++++++++---------- 2 files changed, 52 insertions(+), 45 deletions(-) diff --git a/test/integration/ethereum/addresses.ts b/test/integration/ethereum/addresses.ts index 1683ce92..34dc4870 100644 --- a/test/integration/ethereum/addresses.ts +++ b/test/integration/ethereum/addresses.ts @@ -29,6 +29,10 @@ export const PRODUCTION_ADDRESSES = { pendleEEth0624: "0xc69Ad9baB1dEE23F4605a82b3354F8E40d1E5966", pendleRsEth0624: "0xB05cABCd99cf9a73b19805edefC5f67CA5d1895E", pendleRswEth0624: "0x5cb12D56F5346a016DBBA8CA90635d82e6D1bcEa", + pendleEzEth1226: "0xf7906F274c174A52d444175729E3fa98f9bde285", + pendleEEth0926: "0x1c085195437738d73d75DC64bC5A3E098b7f93b1", + pendleEEth1226: "0x6ee2b5E19ECBa773a352E5B21415Dc419A700d1d", + ezEth: "0xbf5495Efe5DB9ce00f80364C8B423567e58d2110", weEth: "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", rsEth: "0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7", rswEth: "0xFAe103DC9cf190eD75350761e95403b7b8aFa6c0", @@ -69,6 +73,9 @@ export const PRODUCTION_ADDRESSES = { eEth0624: "0xF32e58F92e60f4b0A37A69b95d642A471365EAe8", rsEth0624: "0x4f43c77872db6ba177c270986cd30c3381af37ee", rswEth0624: "0xa9355a5d306c67027c54de0e5a72df76befa5694", + ezEth1226: "0xD8F12bCDE578c653014F27379a6114F67F0e445f", + eEth0926: "0xC8eDd52D0502Aa8b4D5C77361D4B3D300e8fC81c", + eEth1226: "0x7d372819240D14fB477f17b964f95F33BeB4c704", }, }, }, diff --git a/test/integration/ethereum/flashMintHyETH.spec.ts b/test/integration/ethereum/flashMintHyETH.spec.ts index 2ca610db..a6be3e55 100644 --- a/test/integration/ethereum/flashMintHyETH.spec.ts +++ b/test/integration/ethereum/flashMintHyETH.spec.ts @@ -59,7 +59,7 @@ if (process.env.INTEGRATIONTEST) { let debtIssuanceModule: IDebtIssuanceModule; // const collateralTokenAddress = addresses.tokens.stEth; - setBlockNumber(19740000, true); + setBlockNumber(20030042, true); before(async () => { [owner] = await getAccounts(); @@ -130,9 +130,9 @@ if (process.env.INTEGRATIONTEST) { let setToken: SetToken; const components = [ addresses.tokens.instadappEthV2, - addresses.tokens.pendleEEth0624, - addresses.tokens.pendleRsEth0624, - addresses.tokens.pendleRswEth0624, + addresses.tokens.pendleEzEth1226, + addresses.tokens.pendleEEth0926, + addresses.tokens.pendleEEth1226, addresses.tokens.acrossWethLP, addresses.tokens.USDC, ]; @@ -212,80 +212,80 @@ if (process.env.INTEGRATIONTEST) { exchange: 4, }); - const eEthPendleToken = IPendlePrincipalToken__factory.connect( - addresses.tokens.pendleEEth0624, + const ezEth1226PendleToken = IPendlePrincipalToken__factory.connect( + addresses.tokens.pendleEzEth1226, owner.wallet, ); await flashMintHyETH.approveSetToken(setToken.address); - const eEthSyToken = await eEthPendleToken.SY(); + const ezEth1226SyToken = await ezEth1226PendleToken.SY(); await flashMintHyETH.approveToken( - eEthSyToken, - addresses.dexes.pendle.markets.eEth0624, + ezEth1226SyToken, + addresses.dexes.pendle.markets.ezEth1226, MAX_UINT_256, ); await flashMintHyETH.setPendleMarket( - addresses.tokens.pendleEEth0624, - eEthSyToken, - addresses.tokens.weEth, - addresses.dexes.pendle.markets.eEth0624, + addresses.tokens.pendleEzEth1226, + ezEth1226SyToken, + addresses.tokens.ezEth, + addresses.dexes.pendle.markets.ezEth1226, ethers.utils.parseEther("1.0005"), ); - // weETH -> weth pool: https://etherscan.io/address/0x7a415b19932c0105c82fdb6b720bb01b0cc2cae3 - await flashMintHyETH.setSwapData(addresses.tokens.weEth, ADDRESS_ZERO, { - path: [addresses.tokens.weEth, addresses.tokens.weth], - fees: [500], + // ezETH -> weth pool: https://etherscan.io/address/0xbe80225f09645f172b079394312220637c440a63#code + await flashMintHyETH.setSwapData(addresses.tokens.ezEth, ADDRESS_ZERO, { + path: [addresses.tokens.ezEth, addresses.tokens.weth], + fees: [100], pool: ADDRESS_ZERO, exchange: 3, }); - const rsEthPendleToken = IPendlePrincipalToken__factory.connect( - addresses.tokens.pendleRsEth0624, + const pendleEEth0926PendleToken = IPendlePrincipalToken__factory.connect( + addresses.tokens.pendleEEth0926, owner.wallet, ); await flashMintHyETH.approveSetToken(setToken.address); - const rsEthSyToken = await rsEthPendleToken.SY(); + const pendleEEth0926SyToken = await pendleEEth0926PendleToken.SY(); await flashMintHyETH.approveToken( - rsEthSyToken, - addresses.dexes.pendle.markets.rsEth0624, + pendleEEth0926SyToken, + addresses.dexes.pendle.markets.eEth0926, MAX_UINT_256, ); await flashMintHyETH.setPendleMarket( - addresses.tokens.pendleRsEth0624, - rsEthSyToken, - addresses.tokens.rsEth, - addresses.dexes.pendle.markets.rsEth0624, + addresses.tokens.pendleEEth0926, + pendleEEth0926SyToken, + addresses.tokens.weEth, + addresses.dexes.pendle.markets.eEth0926, ethers.utils.parseEther("1.0005"), ); - // rsEth -> weth pool: https://etherscan.io/address/0x059615ebf32c946aaab3d44491f78e4f8e97e1d3 - await flashMintHyETH.setSwapData(addresses.tokens.rsEth, ADDRESS_ZERO, { - path: [addresses.tokens.rsEth, addresses.tokens.weth], + // weETH -> weth pool: https://etherscan.io/address/0x7a415b19932c0105c82fdb6b720bb01b0cc2cae3 + await flashMintHyETH.setSwapData(addresses.tokens.weEth, ADDRESS_ZERO, { + path: [addresses.tokens.weEth, addresses.tokens.weth], fees: [500], pool: ADDRESS_ZERO, exchange: 3, }); - const rswEthPendleToken = IPendlePrincipalToken__factory.connect( - addresses.tokens.pendleRswEth0624, + const pendleEEth1226PendleToken = IPendlePrincipalToken__factory.connect( + addresses.tokens.pendleEEth1226, owner.wallet, ); await flashMintHyETH.approveSetToken(setToken.address); - const rswEthSyToken = await rswEthPendleToken.SY(); + const pendleEEth1226SyToken = await pendleEEth1226PendleToken.SY(); await flashMintHyETH.approveToken( - rswEthSyToken, - addresses.dexes.pendle.markets.rswEth0624, + pendleEEth1226SyToken, + addresses.dexes.pendle.markets.eEth1226, MAX_UINT_256, ); await flashMintHyETH.setPendleMarket( - addresses.tokens.pendleRswEth0624, - rswEthSyToken, - addresses.tokens.rswEth, - addresses.dexes.pendle.markets.rswEth0624, + addresses.tokens.pendleEEth1226, + pendleEEth1226SyToken, + addresses.tokens.weEth, + addresses.dexes.pendle.markets.eEth1226, ethers.utils.parseEther("1.0005"), ); - // rswEth -> weth pool: https://etherscan.io/address/0xe62627326d7794e20bb7261b24985294de1579fe - await flashMintHyETH.setSwapData(addresses.tokens.rswEth, ADDRESS_ZERO, { - path: [addresses.tokens.rswEth, addresses.tokens.weth], - fees: [3000], + // weETH -> weth pool: https://etherscan.io/address/0x7a415b19932c0105c82fdb6b720bb01b0cc2cae3 + await flashMintHyETH.setSwapData(addresses.tokens.weEth, ADDRESS_ZERO, { + path: [addresses.tokens.weEth, addresses.tokens.weth], + fees: [500], pool: ADDRESS_ZERO, exchange: 3, }); @@ -296,9 +296,9 @@ if (process.env.INTEGRATIONTEST) { ["eth", "weth", "USDC"].forEach((inputTokenName: keyof typeof addresses.tokens | "eth") => { describe(`When inputToken is ${inputTokenName}`, () => { - const ethIn = ether(1.01); - const maxAmountIn = inputTokenName == "USDC" ? usdc(3300) : ethIn; - const setTokenAmount = ether(1); + const ethIn = ether(1001); + const maxAmountIn = inputTokenName == "USDC" ? usdc(4000000) : ethIn; + const setTokenAmount = ether(1000); let inputToken: IERC20 | IWETH; let swapDataInputTokenToEth: SwapData; let swapDataEthToInputToken: SwapData;