Skip to content

Commit

Permalink
fix(FlashMintHyETH): Add Pendle exchangeRate() increment handling (#175)
Browse files Browse the repository at this point in the history
* add inflation factor to pendle market data

* update FlashMintHyETH integration tests
  • Loading branch information
pblivin0x authored Jun 6, 2024
1 parent e0cf003 commit 72243db
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 48 deletions.
22 changes: 19 additions & 3 deletions contracts/exchangeIssuance/FlashMintHyETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ contract FlashMintHyETH is Ownable, ReentrancyGuard {
IPendlePrincipalToken pt;
IPendleStandardizedYield sy;
address underlying;
uint256 exchangeRateFactor;
}
/* ============ Constants ============= */

Expand Down Expand Up @@ -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
});
}

/**
Expand All @@ -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");
Expand Down
7 changes: 7 additions & 0 deletions test/integration/ethereum/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -69,6 +73,9 @@ export const PRODUCTION_ADDRESSES = {
eEth0624: "0xF32e58F92e60f4b0A37A69b95d642A471365EAe8",
rsEth0624: "0x4f43c77872db6ba177c270986cd30c3381af37ee",
rswEth0624: "0xa9355a5d306c67027c54de0e5a72df76befa5694",
ezEth1226: "0xD8F12bCDE578c653014F27379a6114F67F0e445f",
eEth0926: "0xC8eDd52D0502Aa8b4D5C77361D4B3D300e8fC81c",
eEth1226: "0x7d372819240D14fB477f17b964f95F33BeB4c704",
},
},
},
Expand Down
93 changes: 48 additions & 45 deletions test/integration/ethereum/flashMintHyETH.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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,
];
Expand Down Expand Up @@ -212,77 +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,
});
Expand All @@ -293,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;
Expand Down

0 comments on commit 72243db

Please sign in to comment.