From aecfb8ce3b4d2155575cda8466864f358308cd2b Mon Sep 17 00:00:00 2001 From: HrikB Date: Wed, 21 Feb 2024 00:02:39 -0500 Subject: [PATCH] test: integration tests (#60) --- .gitmodules | 3 + coverage.sh | 2 +- deployment-config/01_DeployYieldOracle.json | 38 +- .../02_DeployInterestRateModule.json | 17 +- lcov.info | 1939 +++++++++++++++++ lib/solarray | 1 + remappings.txt | 1 + test/helpers/IonPoolSharedSetup.sol | 121 +- test/helpers/MockIonPool.sol | 14 +- test/helpers/YieldOracleSharedSetup.sol | 4 +- .../helpers/weETH/WeEthIonHandlerForkBase.sol | 14 +- .../helpers/weETH/WeEthIonPoolSharedSetup.sol | 15 +- test/integration/concrete/WeEthIonPool.t.sol | 288 +++ test/invariant/IonPool/ActorManager.t.sol | 5 +- test/unit/concrete/YieldOracle.t.sol | 7 + 15 files changed, 2379 insertions(+), 90 deletions(-) create mode 100644 lcov.info create mode 160000 lib/solarray create mode 100644 test/integration/concrete/WeEthIonPool.t.sol diff --git a/.gitmodules b/.gitmodules index 2dcc51b7..dc20147a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "lib/forge-safe"] path = lib/forge-safe url = https://github.com/ind-igo/forge-safe +[submodule "lib/solarray"] + path = lib/solarray + url = https://github.com/evmcheb/solarray diff --git a/coverage.sh b/coverage.sh index bff25b3c..9b924c55 100755 --- a/coverage.sh +++ b/coverage.sh @@ -1,6 +1,6 @@ rm -rf coverage rm -f lcov.info -forge coverage --report lcov +forge coverage --report lcov --ffi delete=false diff --git a/deployment-config/01_DeployYieldOracle.json b/deployment-config/01_DeployYieldOracle.json index da8f2170..4c323270 100644 --- a/deployment-config/01_DeployYieldOracle.json +++ b/deployment-config/01_DeployYieldOracle.json @@ -3,51 +3,41 @@ "weETH": { "address": "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", "historicalExchangeRates": [ - "1031075002100282186", - "1031158812531177075", "1031226095319016479", "1031310415834844310", "1031388291876689267", "1031388291876689267", - "1031542659696644181" + "1031542659696644181", + "1031594042215378342", + "1031701738797902646" ] }, "stader": { "address": "0xcf5EA1b38380f6aF39068375516Daf40Ed70D299", "historicalExchangeRates": [ - "1021458251714077925", - "1021540011059018889", "1021612411074716374", "1021686165920947256", "1021769550207969202", "1021858880545256403", - "1021940599803942448" + "1021940599803942448", + "1022018676921434661", + "1022105684015751204" ] }, "swell": { "address": "0xf951E335afb289353dc249e82926178EaC7DEd78", "historicalExchangeRates": [ - "1050491517818073833", - "1050637173054058672", "1050754209601187151", "1050754209601187151", "1050884470901249618", "1051043935170285905", - "1051043935170285905" + "1051043935170285905", + "1051174925937085597", + "1051320787896182686" ] } }, "dailyBlockData": [ - { - "humanTimestamp": "2024-02-12 06:59:59", - "timestamp": "1707739199", - "blockNumber": "19211804" - }, - { - "humanTimestamp": "2024-02-13 06:59:59", - "timestamp": "1707825599", - "blockNumber": "19218950" - }, { "humanTimestamp": "2024-02-14 06:59:59", "timestamp": "1707911999", @@ -72,6 +62,16 @@ "humanTimestamp": "2024-02-18 06:59:59", "timestamp": "1708257599", "blockNumber": "19254549" + }, + { + "humanTimestamp": "2024-02-19 06:59:59", + "timestamp": "1708343999", + "blockNumber": "19261638" + }, + { + "humanTimestamp": "2024-02-20 06:59:59", + "timestamp": "1708430399", + "blockNumber": "19268776" } ] } \ No newline at end of file diff --git a/deployment-config/02_DeployInterestRateModule.json b/deployment-config/02_DeployInterestRateModule.json index a9f13553..c1530cff 100644 --- a/deployment-config/02_DeployInterestRateModule.json +++ b/deployment-config/02_DeployInterestRateModule.json @@ -1,14 +1,13 @@ { "ilkData": { - "adjustedProfitMargin": "70677685926057170", - "minimumKinkRate": "911013579023514400", + "adjustedProfitMargin": "0", + "minimumKinkRate": "4062570058138700000", "reserveFactor": "0", - "adjustedBaseRate": "68369713930720290", - "minimumBaseRate": "68369713930720290", - "optimalUtilizationRate": "9200", - "distributionFactor": "10000", - "adjustedAboveKinkSlope": "25017682370176442000", - "minimumAboveKinkSlope": "26390655175013278000" + "adjustedBaseRate": "0", + "minimumBaseRate": "1580630071273960000", + "optimalUtilizationRate": "8500", + "adjustedAboveKinkSlope": "0", + "minimumAboveKinkSlope": "23863999665252300000" }, - "yieldOracleAddress": "0x437CC840e234C2127f54CD59B0B18aF59c586760" + "yieldOracleAddress": "0x31403b1e52051883f2Ce1B1b4C89f36034e1221D" } diff --git a/lcov.info b/lcov.info new file mode 100644 index 00000000..e4b15b01 --- /dev/null +++ b/lcov.info @@ -0,0 +1,1939 @@ +TN: +SF:src/InterestRate.sol +FN:188,InterestRate._packCollateralConfig +FNDA:0,InterestRate._packCollateralConfig +DA:196,0 +BRDA:196,0,0,- +BRDA:196,0,1,- +DA:198,0 +DA:200,0 +DA:205,0 +DA:213,0 +FN:225,InterestRate.unpackCollateralConfig +FNDA:120,InterestRate.unpackCollateralConfig +DA:226,120 +FN:229,InterestRate._unpackCollateralConfig +FNDA:687099,InterestRate._unpackCollateralConfig +DA:230,687099 +BRDA:230,1,0,- +BRDA:230,1,1,687099 +DA:232,687099 +DA:233,687099 +DA:234,687099 +DA:236,687099 +BRDA:236,2,0,254928 +BRDA:236,2,1,432171 +DA:237,254928 +DA:238,254928 +DA:239,254928 +DA:240,432171 +BRDA:240,3,0,290209 +BRDA:240,3,1,141962 +DA:241,290209 +DA:242,290209 +DA:243,290209 +DA:244,141962 +BRDA:244,4,0,141962 +BRDA:244,4,1,- +DA:245,141962 +DA:246,141962 +DA:247,141962 +DA:248,0 +BRDA:248,5,0,- +BRDA:248,5,1,- +DA:249,0 +DA:250,0 +DA:251,0 +DA:252,0 +BRDA:252,6,0,- +BRDA:252,6,1,- +DA:253,0 +DA:254,0 +DA:255,0 +DA:256,0 +BRDA:256,7,0,- +BRDA:256,7,1,- +DA:257,0 +DA:258,0 +DA:259,0 +DA:260,0 +BRDA:260,8,0,- +BRDA:260,8,1,- +DA:261,0 +DA:262,0 +DA:263,0 +DA:264,0 +BRDA:264,9,0,- +BRDA:264,9,1,- +DA:265,0 +DA:266,0 +DA:267,0 +DA:270,687099 +DA:271,687099 +DA:272,687099 +DA:274,687099 +DA:275,687099 +DA:276,687099 +DA:277,687099 +DA:278,687099 +DA:280,687099 +DA:281,687099 +DA:282,687099 +DA:283,687099 +DA:285,687099 +FN:306,InterestRate.calculateInterestRate +FNDA:686979,InterestRate.calculateInterestRate +DA:315,686979 +DA:316,686979 +DA:317,686979 +DA:319,686979 +DA:325,686979 +BRDA:325,10,0,- +BRDA:325,10,1,686979 +DA:326,0 +DA:329,686979 +DA:330,686979 +DA:333,686979 +DA:335,686979 +DA:337,686979 +DA:344,686979 +BRDA:344,11,0,- +BRDA:344,11,1,686979 +DA:345,0 +DA:348,686979 +DA:351,686979 +DA:352,686979 +DA:355,686979 +BRDA:355,12,0,5 +BRDA:355,12,1,648280 +DA:356,648285 +DA:357,648285 +DA:359,648285 +BRDA:359,13,0,5 +BRDA:359,13,1,648280 +DA:360,5 +DA:362,648280 +DA:370,38694 +DA:372,38694 +DA:373,38694 +DA:374,38694 +DA:375,38694 +DA:378,38694 +DA:379,38694 +DA:381,38694 +BRDA:381,14,0,7588 +BRDA:381,14,1,31106 +DA:382,7588 +DA:384,31106 +FNF:4 +FNH:3 +LF:87 +LH:60 +BRF:30 +BRH:14 +end_of_record +TN: +SF:src/IonPool.sol +FN:155,IonPool._getIonPoolStorage +FNDA:43776488,IonPool._getIonPoolStorage +DA:157,43776488 +FN:165,IonPool.initialize +FNDA:422,IonPool.initialize +DA:178,378 +DA:179,378 +DA:181,378 +DA:183,378 +DA:185,378 +DA:186,378 +DA:188,378 +DA:189,378 +FN:200,IonPool.initializeIlk +FNDA:1360,IonPool.initializeIlk +DA:201,1359 +DA:203,1359 +BRDA:203,0,0,1 +BRDA:203,0,1,1358 +DA:204,1358 +BRDA:204,1,0,1 +BRDA:204,1,1,1357 +DA:206,1357 +DA:209,1357 +BRDA:209,2,0,1 +BRDA:209,2,1,1356 +DA:213,1356 +DA:214,1356 +DA:215,1356 +DA:216,1356 +DA:218,1356 +DA:220,1356 +DA:222,1356 +FN:230,IonPool.updateIlkSpot +FNDA:1108,IonPool.updateIlkSpot +DA:231,1105 +DA:233,1105 +DA:235,1105 +FN:246,IonPool.updateIlkDebtCeiling +FNDA:91697,IonPool.updateIlkDebtCeiling +DA:247,91694 +DA:249,91694 +DA:251,91694 +FN:263,IonPool.updateIlkDust +FNDA:20010,IonPool.updateIlkDust +DA:264,20007 +DA:266,20007 +DA:268,20007 +FN:278,IonPool.updateSupplyCap +FNDA:20381,IonPool.updateSupplyCap +DA:279,20381 +DA:281,20381 +DA:283,20381 +FN:292,IonPool.updateInterestRateModule +FNDA:5,IonPool.updateInterestRateModule +DA:293,4 +BRDA:293,3,0,1 +BRDA:293,3,1,3 +DA:295,3 +DA:298,3 +BRDA:298,4,0,1 +BRDA:298,4,1,1 +DA:299,1 +DA:301,1 +DA:303,1 +FN:310,IonPool.updateWhitelist +FNDA:27,IonPool.updateWhitelist +DA:311,26 +BRDA:311,5,0,1 +BRDA:311,5,1,25 +DA:313,25 +DA:315,25 +DA:317,25 +FN:330,IonPool.pause +FNDA:5,IonPool.pause +DA:331,4 +DA:332,4 +FN:340,IonPool.unpause +FNDA:3,IonPool.unpause +DA:341,2 +DA:342,1 +DA:344,1 +DA:345,1 +DA:347,3 +DA:350,3 +FN:360,IonPool.accrueInterest +FNDA:2,IonPool.accrueInterest +DA:361,1 +FN:364,IonPool._accrueInterest +FNDA:2760981,IonPool._accrueInterest +DA:365,2760981 +DA:367,2760981 +DA:369,2760981 +DA:370,2760981 +DA:371,2760981 +DA:373,2760981 +DA:374,2760981 +DA:375,8211581 +DA:381,8211581 +DA:383,8211581 +BRDA:383,6,0,- +BRDA:383,6,1,492502 +DA:384,492502 +DA:385,492502 +DA:386,492502 +DA:387,492502 +DA:389,492502 +DA:390,492502 +DA:394,8211581 +DA:397,2760981 +DA:398,2760981 +DA:399,2760981 +DA:400,2760981 +FN:403,IonPool.calculateRewardAndDebtDistribution +FNDA:260005,IonPool.calculateRewardAndDebtDistribution +DA:415,1034230 +DA:417,1034230 +DA:419,1034230 +DA:420,1034230 +DA:422,1034230 +DA:424,1034230 +DA:425,3102648 +DA:431,3102648 +DA:433,3102648 +BRDA:433,7,0,- +BRDA:433,7,1,265194 +DA:434,265194 +DA:435,265194 +DA:436,265194 +DA:438,265194 +DA:439,265194 +DA:443,3102648 +FN:454,IonPool.calculateRewardAndDebtDistributionForIlk +FNDA:180003,IonPool.calculateRewardAndDebtDistributionForIlk +DA:459,2528684 +FN:463,IonPool._calculateRewardAndDebtDistributionForIlk +FNDA:13842913,IonPool._calculateRewardAndDebtDistributionForIlk +DA:477,13842913 +DA:478,13842913 +DA:480,13842913 +DA:481,13842913 +BRDA:481,8,0,13155934 +BRDA:481,8,1,686979 +DA:485,13155934 +DA:488,686979 +DA:490,686979 +DA:491,686979 +DA:493,686979 +BRDA:493,9,0,100640 +BRDA:493,9,1,586339 +DA:496,586339 +DA:499,586339 +DA:510,586339 +DA:512,586339 +DA:515,586339 +DA:518,586339 +DA:523,586339 +FN:536,IonPool.withdraw +FNDA:41920,IonPool.withdraw +DA:537,41918 +DA:538,41918 +DA:540,41918 +DA:542,41917 +DA:543,41917 +DA:545,41917 +FN:555,IonPool.supply +FNDA:120522,IonPool.supply +DA:564,120519 +DA:565,120519 +DA:567,120519 +DA:569,120519 +DA:571,120519 +DA:572,120519 +BRDA:572,10,0,20001 +BRDA:572,10,1,100518 +DA:574,100518 +FN:587,IonPool.borrow +FNDA:826562,IonPool.borrow +DA:598,826557 +DA:599,826557 +DA:600,826557 +DA:602,766545 +FN:612,IonPool.repay +FNDA:335176,IonPool.repay +DA:621,335175 +DA:622,335175 +DA:623,335175 +DA:625,305172 +FN:635,IonPool.withdrawCollateral +FNDA:245188,IonPool.withdrawCollateral +DA:644,245186 +DA:645,245186 +DA:647,215183 +FN:658,IonPool.depositCollateral +FNDA:1171620,IonPool.depositCollateral +DA:669,1171616 +DA:670,1171616 +DA:672,1141613 +FN:677,IonPool._modifyPosition +FNDA:2578534,IonPool._modifyPosition +DA:688,2578534 +DA:690,2578534 +DA:692,2578534 +BRDA:692,11,0,- +BRDA:692,11,1,2578534 +DA:694,2578534 +DA:695,2578534 +DA:696,2578534 +DA:698,2578534 +DA:702,2578534 +DA:705,2578534 +BRDA:704,12,0,- +BRDA:704,12,1,3 +DA:710,3 +DA:712,2578531 +DA:715,2578531 +BRDA:714,13,0,30003 +BRDA:714,13,1,2548528 +DA:719,30003 +DA:722,2548528 +BRDA:722,14,0,60006 +BRDA:722,14,1,2488522 +DA:723,60006 +DA:727,2488522 +BRDA:727,15,0,30003 +BRDA:727,15,1,2458519 +DA:728,30003 +DA:735,2458519 +BRDA:735,16,0,30003 +BRDA:735,16,1,2428516 +DA:736,30003 +DA:740,2428516 +BRDA:740,17,0,- +BRDA:740,17,1,3 +DA:741,3 +DA:745,2428513 +DA:747,2428513 +DA:748,2428513 +DA:749,2428513 +DA:750,2428513 +DA:751,2428513 +DA:755,2428513 +FN:766,IonPool.repayBadDebt +FNDA:3923,IonPool.repayBadDebt +DA:767,3922 +DA:769,3922 +DA:770,3922 +DA:771,3922 +DA:774,3922 +DA:776,3922 +FN:787,IonPool._transferWeth +FNDA:2432435,IonPool._transferWeth +DA:788,2432435 +BRDA:788,18,0,989438 +BRDA:788,18,1,2432435 +DA:789,989438 +DA:791,989438 +BRDA:791,19,0,165538 +BRDA:791,19,1,272842 +DA:792,272842 +DA:793,272842 +DA:794,272842 +BRDA:794,20,0,165538 +BRDA:794,20,1,272842 +DA:796,272842 +DA:797,272842 +DA:800,716596 +DA:802,716596 +DA:804,716596 +FN:819,IonPool.confiscateVault +FNDA:20007,IonPool.confiscateVault +DA:831,20005 +DA:833,20005 +DA:835,20005 +DA:836,20005 +DA:837,20005 +DA:839,20005 +DA:840,20005 +DA:841,20005 +DA:844,20005 +DA:846,20005 +DA:847,20005 +DA:848,20005 +DA:850,20005 +FN:862,IonPool.mintAndBurnGem +FNDA:1386735,IonPool.mintAndBurnGem +DA:863,1386734 +DA:865,1386734 +DA:867,1386734 +FN:877,IonPool.transferGem +FNDA:90011,IonPool.transferGem +DA:878,90009 +BRDA:878,21,0,30003 +BRDA:878,21,1,60006 +DA:880,60006 +DA:882,60006 +DA:883,60006 +DA:884,60006 +FN:892,IonPool.ilkCount +FNDA:1269193,IonPool.ilkCount +DA:893,1269193 +DA:894,1269193 +FN:900,IonPool.getIlkIndex +FNDA:120,IonPool.getIlkIndex +DA:901,120 +DA:902,120 +DA:906,120 +FN:912,IonPool.getIlkAddress +FNDA:1413,IonPool.getIlkAddress +DA:913,1413 +DA:914,1413 +FN:920,IonPool.addressContains +FNDA:120,IonPool.addressContains +DA:921,120 +DA:922,120 +FN:929,IonPool.totalNormalizedDebt +FNDA:530049,IonPool.totalNormalizedDebt +DA:930,530049 +DA:931,530049 +FN:934,IonPool.rateUnaccrued +FNDA:6,IonPool.rateUnaccrued +DA:935,6 +DA:936,6 +FN:942,IonPool.rate +FNDA:2348681,IonPool.rate +DA:943,2348681 +DA:945,2348681 +DA:947,2348681 +FN:954,IonPool.lastRateUpdate +FNDA:13,IonPool.lastRateUpdate +DA:955,13 +DA:956,13 +FN:962,IonPool.spot +FNDA:401438,IonPool.spot +DA:963,401438 +DA:964,401438 +FN:970,IonPool.debtCeiling +FNDA:127,IonPool.debtCeiling +DA:971,127 +DA:972,127 +FN:978,IonPool.dust +FNDA:4046,IonPool.dust +DA:979,4046 +DA:980,4046 +FN:986,IonPool.collateral +FNDA:1601238,IonPool.collateral +DA:987,1601238 +DA:988,1601238 +FN:994,IonPool.normalizedDebt +FNDA:1598204,IonPool.normalizedDebt +DA:995,1598204 +DA:996,1598204 +FN:1002,IonPool.vault +FNDA:20008,IonPool.vault +DA:1003,20008 +DA:1004,20008 +FN:1010,IonPool.gem +FNDA:781589,IonPool.gem +DA:1011,781589 +DA:1012,781589 +FN:1018,IonPool.unbackedDebt +FNDA:1708,IonPool.unbackedDebt +DA:1019,1708 +DA:1020,1708 +FN:1026,IonPool.isOperator +FNDA:2,IonPool.isOperator +DA:1027,2 +DA:1028,2 +FN:1035,IonPool.isAllowed +FNDA:0,IonPool.isAllowed +DA:1036,7585578 +DA:1038,7585578 +FN:1041,IonPool.debtUnaccrued +FNDA:180002,IonPool.debtUnaccrued +DA:1042,180002 +DA:1043,180002 +FN:1050,IonPool.debt +FNDA:226296,IonPool.debt +DA:1051,226296 +DA:1053,226296 +DA:1055,226296 +FN:1061,IonPool.totalUnbackedDebt +FNDA:0,IonPool.totalUnbackedDebt +DA:1062,0 +DA:1063,0 +FN:1069,IonPool.interestRateModule +FNDA:1,IonPool.interestRateModule +DA:1070,1 +DA:1071,1 +FN:1077,IonPool.whitelist +FNDA:14,IonPool.whitelist +DA:1078,14 +DA:1079,14 +FN:1085,IonPool.weth +FNDA:1043626,IonPool.weth +DA:1086,1043626 +DA:1087,1043626 +FN:1093,IonPool.getCurrentBorrowRate +FNDA:0,IonPool.getCurrentBorrowRate +DA:1094,0 +DA:1096,0 +DA:1097,0 +DA:1098,0 +DA:1100,0 +DA:1102,0 +DA:1103,0 +FN:1110,IonPool.implementation +FNDA:44,IonPool.implementation +DA:1111,44 +FN:1120,IonPool.addOperator +FNDA:710116,IonPool.addOperator +DA:1121,710116 +DA:1123,710116 +DA:1125,710116 +FN:1132,IonPool.removeOperator +FNDA:1,IonPool.removeOperator +DA:1133,1 +DA:1135,1 +DA:1137,1 +FN:1142,IonPool._add +FNDA:11620864,IonPool._add +DA:1145,11620864 +DA:1147,11620864 +BRDA:1147,22,0,1475 +BRDA:1147,22,1,11619389 +DA:1148,11619389 +BRDA:1148,23,0,608 +BRDA:1148,23,1,11618781 +FN:1151,IonPool._sub +FNDA:2498528,IonPool._sub +DA:1154,2498528 +DA:1156,2498528 +BRDA:1156,24,0,3244 +BRDA:1156,24,1,2495284 +DA:1157,2495284 +BRDA:1157,25,0,730 +BRDA:1157,25,1,2494554 +FN:1170,IonPool._rpow +FNDA:586339,IonPool._rpow +FN:1203,IonPool.either +FNDA:12712637,IonPool.either +DA:1205,12712637 +FN:1209,IonPool.both +FNDA:15081150,IonPool.both +DA:1211,15081150 +FNF:61 +FNH:58 +LF:271 +LH:262 +BRF:52 +BRH:47 +end_of_record +TN: +SF:src/Liquidation.sol +FN:157,Liquidation._getConfig +FNDA:20008,Liquidation._getConfig +DA:158,20008 +DA:159,20008 +DA:160,20008 +FN:170,Liquidation.getRepayAmt +FNDA:0,Liquidation.getRepayAmt +DA:171,0 +DA:174,0 +DA:175,0 +DA:176,0 +DA:178,0 +BRDA:178,0,0,- +BRDA:178,0,1,- +DA:179,0 +DA:189,0 +DA:191,0 +DA:192,0 +BRDA:192,1,0,- +BRDA:192,1,1,- +DA:193,0 +DA:196,0 +DA:197,0 +DA:199,0 +DA:201,0 +BRDA:201,2,0,- +BRDA:201,2,1,- +DA:202,0 +BRDA:202,3,0,- +BRDA:202,3,1,- +DA:204,0 +FN:215,Liquidation._getRepayAmt +FNDA:20005,Liquidation._getRepayAmt +DA:232,20005 +DA:233,20005 +DA:234,20005 +FN:253,Liquidation.liquidate +FNDA:20008,Liquidation.liquidate +DA:261,20008 +DA:263,20008 +DA:266,20008 +DA:267,20008 +DA:268,20008 +DA:270,20008 +BRDA:270,4,0,1 +BRDA:270,4,1,20007 +DA:271,1 +DA:281,20007 +DA:283,20007 +DA:284,20007 +BRDA:284,5,0,2 +BRDA:284,5,1,20005 +DA:285,2 +DA:288,20005 +DA:289,20005 +DA:290,20005 +DA:292,20005 +DA:308,20005 +BRDA:308,6,0,- +BRDA:308,6,1,16083 +DA:310,16083 +DA:311,16083 +DA:312,16083 +DA:315,16083 +DA:316,16083 +DA:317,3922 +BRDA:317,7,0,141 +BRDA:317,7,1,3781 +DA:319,141 +DA:320,141 +DA:321,141 +DA:325,3781 +DA:326,3781 +BRDA:326,8,0,3781 +BRDA:326,8,1,3781 +DA:328,3781 +DA:329,3781 +DA:335,3922 +DA:336,3922 +BRDA:336,9,0,1863 +BRDA:336,9,1,3922 +DA:339,3922 +DA:343,3922 +DA:348,3922 +DA:350,3922 +DA:352,3922 +FNF:4 +FNH:3 +LF:58 +LH:42 +BRF:20 +BRH:11 +end_of_record +TN: +SF:src/Whitelist.sol +FN:55,Whitelist.updateBorrowersRoot +FNDA:34,Whitelist.updateBorrowersRoot +DA:56,34 +FN:63,Whitelist.updateLendersRoot +FNDA:4,Whitelist.updateLendersRoot +DA:64,4 +FN:71,Whitelist.approveProtocolWhitelist +FNDA:31,Whitelist.approveProtocolWhitelist +DA:72,31 +FN:79,Whitelist.revokeProtocolWhitelist +FNDA:2,Whitelist.revokeProtocolWhitelist +DA:80,2 +FN:90,Whitelist.isWhitelistedBorrower +FNDA:2498283,Whitelist.isWhitelistedBorrower +DA:100,2498283 +BRDA:100,0,0,51 +BRDA:100,0,1,2498232 +DA:101,2498232 +DA:102,2498232 +BRDA:102,1,0,2498159 +BRDA:102,1,1,73 +DA:103,73 +DA:104,73 +BRDA:104,2,0,56 +BRDA:104,2,1,17 +DA:105,56 +DA:107,17 +FN:118,Whitelist.isWhitelistedLender +FNDA:120531,Whitelist.isWhitelistedLender +DA:127,120531 +BRDA:127,3,0,2 +BRDA:127,3,1,120529 +DA:128,120529 +DA:129,120529 +BRDA:129,4,0,120508 +BRDA:129,4,1,21 +DA:130,21 +DA:131,21 +BRDA:131,5,0,15 +BRDA:131,5,1,6 +DA:132,15 +DA:134,6 +FNF:6 +FNH:6 +LF:18 +LH:18 +BRF:12 +BRH:12 +end_of_record +TN: +SF:src/YieldOracle.sol +FN:126,YieldOracle.updateIonPool +FNDA:386,YieldOracle.updateIonPool +DA:127,386 +FN:138,YieldOracle.updateAll +FNDA:25,YieldOracle.updateAll +DA:139,25 +BRDA:139,0,0,- +BRDA:139,0,1,24 +DA:140,25 +FN:152,YieldOracle._updateAll +FNDA:25,YieldOracle._updateAll +DA:153,25 +BRDA:153,1,0,1 +BRDA:153,1,1,24 +DA:155,24 +DA:156,24 +DA:158,24 +DA:159,70 +DA:160,70 +DA:163,70 +BRDA:163,2,0,1 +BRDA:163,2,1,69 +DA:173,69 +DA:174,69 +BRDA:174,3,0,68 +BRDA:174,3,1,69 +DA:175,68 +DA:179,68 +DA:185,68 +DA:188,69 +DA:191,69 +DA:193,69 +DA:196,69 +DA:200,23 +DA:202,23 +FN:210,YieldOracle._getExchangeRate +FNDA:70,YieldOracle._getExchangeRate +DA:211,70 +BRDA:211,4,0,- +BRDA:211,4,1,24 +DA:212,24 +DA:213,24 +DA:214,46 +BRDA:214,5,0,- +BRDA:214,5,1,23 +DA:215,23 +DA:216,23 +DA:217,23 +BRDA:217,6,0,- +BRDA:217,6,1,23 +DA:218,23 +DA:219,23 +DA:221,0 +FNF:4 +FNH:4 +LF:31 +LH:30 +BRF:14 +BRH:10 +end_of_record +TN: +SF:src/admin/ProxyAdmin.sol +FN:44,ProxyAdmin.upgradeAndCall +FNDA:0,ProxyAdmin.upgradeAndCall +DA:54,0 +FNF:1 +FNH:0 +LF:1 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/admin/TransparentUpgradeableProxy.sol +FN:91,TransparentUpgradeableProxy._proxyAdmin +FNDA:0,TransparentUpgradeableProxy._proxyAdmin +DA:92,0 +FN:98,TransparentUpgradeableProxy._fallback +FNDA:0,TransparentUpgradeableProxy._fallback +DA:99,0 +BRDA:99,0,0,- +BRDA:99,0,1,- +DA:100,0 +BRDA:100,1,0,- +BRDA:100,1,1,- +DA:101,0 +DA:103,0 +DA:106,0 +FN:117,TransparentUpgradeableProxy._dispatchUpgradeToAndCall +FNDA:0,TransparentUpgradeableProxy._dispatchUpgradeToAndCall +DA:118,0 +DA:119,0 +FNF:3 +FNH:0 +LF:8 +LH:0 +BRF:4 +BRH:0 +end_of_record +TN: +SF:src/flash/handlers/EthXHandler.sol +FN:65,EthXHandler._depositWethForLst +FNDA:31082,EthXHandler._depositWethForLst +DA:66,31082 +DA:67,31082 +FN:76,EthXHandler._getEthAmountInForLstAmountOut +FNDA:50999,EthXHandler._getEthAmountInForLstAmountOut +DA:77,50999 +FNF:2 +FNH:2 +LF:3 +LH:3 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/flash/handlers/SwEthHandler.sol +FN:50,SwEthHandler._depositWethForLst +FNDA:30891,SwEthHandler._depositWethForLst +DA:51,30891 +DA:52,30891 +FN:61,SwEthHandler._getEthAmountInForLstAmountOut +FNDA:50901,SwEthHandler._getEthAmountInForLstAmountOut +DA:62,50901 +FNF:2 +FNH:2 +LF:3 +LH:3 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/flash/handlers/WeEthHandler.sol +FN:47,WeEthHandler._mintCollateralAsset +FNDA:15652,WeEthHandler._mintCollateralAsset +DA:48,15652 +DA:49,15652 +FN:55,WeEthHandler._getAmountInForCollateralAmountOut +FNDA:20005,WeEthHandler._getAmountInForCollateralAmountOut +DA:56,20005 +FNF:2 +FNH:2 +LF:3 +LH:3 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/flash/handlers/WstEthHandler.sol +FN:54,WstEthHandler._depositWethForLst +FNDA:77126,WstEthHandler._depositWethForLst +DA:55,77126 +DA:56,77126 +FN:65,WstEthHandler._getEthAmountInForLstAmountOut +FNDA:127117,WstEthHandler._getEthAmountInForLstAmountOut +DA:66,127117 +FN:69,WstEthHandler.zapDepositAndBorrow +FNDA:30009,WstEthHandler.zapDepositAndBorrow +DA:77,30008 +DA:78,30008 +DA:79,30008 +FN:82,WstEthHandler.zapFlashLeverageCollateral +FNDA:30006,WstEthHandler.zapFlashLeverageCollateral +DA:91,30004 +BRDA:91,0,0,- +BRDA:91,0,1,30002 +DA:92,30002 +DA:93,30002 +DA:96,30004 +DA:97,30004 +DA:98,30004 +FN:101,WstEthHandler.zapFlashLeverageWeth +FNDA:30005,WstEthHandler.zapFlashLeverageWeth +DA:110,30004 +BRDA:110,1,0,- +BRDA:110,1,1,30002 +DA:111,30002 +DA:112,30002 +DA:115,30004 +DA:116,30004 +DA:117,30004 +FN:120,WstEthHandler.zapFlashswapLeverage +FNDA:30009,WstEthHandler.zapFlashswapLeverage +DA:132,30004 +BRDA:132,2,0,- +BRDA:132,2,1,30002 +DA:133,30002 +DA:134,30002 +DA:137,30004 +DA:138,30004 +DA:140,30004 +FNF:6 +FNH:6 +LF:24 +LH:24 +BRF:6 +BRH:3 +end_of_record +TN: +SF:src/flash/handlers/base/BalancerFlashloanDirectMintHandler.sol +FN:60,BalancerFlashloanDirectMintHandler.flashLeverageCollateral +FNDA:60010,BalancerFlashloanDirectMintHandler.flashLeverageCollateral +DA:69,60009 +DA:70,60009 +FN:78,BalancerFlashloanDirectMintHandler._flashLeverageCollateral +FNDA:90013,BalancerFlashloanDirectMintHandler._flashLeverageCollateral +DA:85,90013 +DA:87,90013 +BRDA:87,0,0,20511 +BRDA:87,0,1,69502 +DA:89,20511 +DA:90,20511 +DA:93,69502 +DA:94,69502 +DA:96,69502 +DA:97,69502 +DA:99,69502 +DA:100,69502 +BRDA:100,1,0,- +BRDA:100,1,1,69502 +DA:101,0 +DA:105,69502 +DA:107,69502 +DA:114,69502 +FN:130,BalancerFlashloanDirectMintHandler.flashLeverageWeth +FNDA:60010,BalancerFlashloanDirectMintHandler.flashLeverageWeth +DA:140,60009 +DA:141,60009 +FN:149,BalancerFlashloanDirectMintHandler._flashLeverageWeth +FNDA:90013,BalancerFlashloanDirectMintHandler._flashLeverageWeth +DA:156,90013 +DA:157,90013 +DA:159,90013 +DA:160,90013 +DA:162,90013 +BRDA:162,2,0,20416 +BRDA:162,2,1,69597 +DA:164,20416 +DA:165,20416 +DA:176,69597 +BRDA:176,3,0,- +BRDA:176,3,1,69597 +DA:177,0 +DA:180,69597 +DA:181,69597 +DA:183,69597 +DA:185,69597 +DA:192,69597 +FN:211,BalancerFlashloanDirectMintHandler.receiveFlashLoan +FNDA:139123,BalancerFlashloanDirectMintHandler.receiveFlashLoan +DA:220,139123 +BRDA:220,4,0,6 +BRDA:220,4,1,139117 +DA:221,139117 +BRDA:221,5,0,6 +BRDA:221,5,1,139111 +DA:222,139111 +BRDA:222,6,0,12 +BRDA:222,6,1,139099 +DA:224,139099 +DA:225,139099 +DA:226,139099 +DA:229,139099 +BRDA:229,7,0,- +BRDA:229,7,1,69597 +DA:230,69597 +DA:233,69597 +BRDA:233,8,0,- +BRDA:233,8,1,69597 +DA:236,69597 +DA:238,69597 +DA:240,69502 +BRDA:240,9,0,- +BRDA:240,9,1,69502 +DA:242,69502 +DA:245,69502 +BRDA:245,10,0,- +BRDA:245,10,1,69502 +DA:248,69502 +DA:251,69502 +DA:253,69502 +FNF:5 +FNH:5 +LF:49 +LH:47 +BRF:22 +BRH:16 +end_of_record +TN: +SF:src/flash/handlers/base/IonHandlerBase.sol +FN:118,IonHandlerBase.depositAndBorrow +FNDA:4,IonHandlerBase.depositAndBorrow +DA:126,4 +DA:127,4 +FN:143,IonHandlerBase._depositAndBorrow +FNDA:500084,IonHandlerBase._depositAndBorrow +DA:152,500084 +DA:154,500084 +DA:156,500084 +BRDA:156,0,0,395333 +BRDA:156,0,1,500084 +DA:158,395333 +DA:160,395333 +DA:161,395333 +BRDA:161,1,0,365327 +BRDA:161,1,1,30006 +DA:162,365327 +DA:164,30006 +DA:167,395333 +FN:183,IonHandlerBase.repayFullAndWithdraw +FNDA:0,IonHandlerBase.repayFullAndWithdraw +DA:184,0 +DA:186,0 +DA:188,0 +DA:190,0 +DA:192,0 +FN:206,IonHandlerBase._getFullRepayAmount +FNDA:66815,IonHandlerBase._getFullRepayAmount +DA:207,66815 +DA:209,66815 +DA:213,66815 +DA:214,66815 +DA:215,66815 +BRDA:215,2,0,37633 +BRDA:215,2,1,66815 +FN:227,IonHandlerBase.repayAndWithdraw +FNDA:2,IonHandlerBase.repayAndWithdraw +DA:228,2 +DA:229,2 +FN:241,IonHandlerBase._repayAndWithdraw +FNDA:125137,IonHandlerBase._repayAndWithdraw +DA:249,125137 +DA:251,125137 +DA:253,125137 +DA:255,125137 +DA:257,125137 +FNF:6 +FNH:5 +LF:28 +LH:23 +BRF:6 +BRH:6 +end_of_record +TN: +SF:src/flash/handlers/base/UniswapFlashloanBalancerSwapHandler.sol +FN:91,UniswapFlashloanBalancerSwapHandler.flashLeverageWethAndSwap +FNDA:60016,UniswapFlashloanBalancerSwapHandler.flashLeverageWethAndSwap +DA:103,60013 +DA:104,60013 +DA:106,60013 +BRDA:106,0,0,13196 +BRDA:106,0,1,46817 +DA:108,13196 +DA:109,13196 +DA:112,46817 +DA:114,46817 +DA:124,46817 +DA:131,46817 +DA:132,46817 +DA:133,46817 +DA:134,46817 +DA:135,46817 +DA:137,46817 +DA:138,46817 +DA:139,46817 +BRDA:139,1,0,- +BRDA:139,1,1,46817 +DA:140,46817 +DA:142,46817 +FN:159,UniswapFlashloanBalancerSwapHandler.flashDeleverageWethAndSwap +FNDA:40014,UniswapFlashloanBalancerSwapHandler.flashDeleverageWethAndSwap +DA:167,40008 +BRDA:167,2,0,20003 +BRDA:167,2,1,40008 +DA:168,20003 +DA:171,40008 +BRDA:171,3,0,31294 +BRDA:171,3,1,40006 +DA:173,31294 +DA:174,31294 +DA:175,31294 +BRDA:175,4,0,- +BRDA:175,4,1,31294 +DA:176,31294 +DA:178,31294 +FN:231,UniswapFlashloanBalancerSwapHandler.uniswapV3FlashCallback +FNDA:78113,UniswapFlashloanBalancerSwapHandler.uniswapV3FlashCallback +DA:232,78113 +BRDA:232,5,0,2 +BRDA:232,5,1,78111 +DA:234,78111 +DA:236,78111 +DA:243,78111 +DA:245,78111 +BRDA:245,6,0,- +BRDA:245,6,1,46815 +DA:246,46817 +DA:248,46817 +DA:249,46817 +DA:250,46817 +DA:252,46817 +DA:253,46817 +BRDA:253,7,0,2 +BRDA:253,7,1,46815 +DA:254,2 +DA:257,46815 +DA:270,46815 +DA:273,46815 +BRDA:273,8,0,- +BRDA:273,8,1,46815 +DA:275,46815 +DA:276,46815 +DA:278,46815 +DA:281,31294 +DA:283,31294 +DA:290,31294 +DA:291,31294 +BRDA:291,9,0,2 +BRDA:291,9,1,31292 +DA:292,2 +DA:295,31292 +DA:297,31292 +DA:306,31292 +DA:308,31292 +FN:319,UniswapFlashloanBalancerSwapHandler._simulateGivenOutBalancerSwap +FNDA:78111,UniswapFlashloanBalancerSwapHandler._simulateGivenOutBalancerSwap +DA:328,78111 +DA:329,78111 +DA:331,78111 +DA:339,78111 +DA:340,78111 +DA:341,78111 +DA:343,78111 +DA:344,78111 +DA:346,78111 +FNF:4 +FNH:4 +LF:62 +LH:62 +BRF:20 +BRH:16 +end_of_record +TN: +SF:src/flash/handlers/base/UniswapFlashswapDirectMintHandler.sol +FN:83,UniswapFlashswapDirectMintHandler.flashswapAndMint +FNDA:20005,UniswapFlashswapDirectMintHandler.flashswapAndMint +DA:94,20005 +DA:95,20005 +FN:98,UniswapFlashswapDirectMintHandler._flashswapAndMint +FNDA:20005,UniswapFlashswapDirectMintHandler._flashswapAndMint +DA:105,20005 +DA:106,20005 +DA:108,20005 +BRDA:108,0,0,4353 +BRDA:108,0,1,15652 +DA:110,4353 +DA:111,4353 +DA:115,15652 +DA:116,15652 +DA:123,15652 +BRDA:123,1,0,2 +BRDA:123,1,1,15650 +DA:124,2 +FN:136,UniswapFlashswapDirectMintHandler._initiateFlashSwap +FNDA:15652,UniswapFlashswapDirectMintHandler._initiateFlashSwap +DA:145,15652 +DA:149,15652 +DA:150,15652 +DA:155,15652 +BRDA:155,2,0,- +BRDA:155,2,1,15652 +FN:172,UniswapFlashswapDirectMintHandler.uniswapV3SwapCallback +FNDA:15654,UniswapFlashswapDirectMintHandler.uniswapV3SwapCallback +DA:173,15654 +BRDA:173,3,0,2 +BRDA:173,3,1,15652 +DA:176,15652 +BRDA:176,4,0,- +BRDA:176,4,1,15652 +DA:177,15652 +DA:178,15652 +DA:182,15652 +BRDA:182,5,0,15652 +BRDA:182,5,1,15652 +DA:183,15652 +DA:186,15652 +DA:189,15652 +BRDA:189,6,0,- +BRDA:189,6,1,15652 +DA:192,15652 +DA:195,15652 +BRDA:195,7,0,- +BRDA:195,7,1,15652 +DA:199,15652 +DA:203,15652 +FNF:4 +FNH:4 +LF:27 +LH:27 +BRF:16 +BRH:12 +end_of_record +TN: +SF:src/flash/handlers/base/UniswapFlashswapHandler.sol +FN:97,UniswapFlashswapHandler.flashswapLeverage +FNDA:180033,UniswapFlashswapHandler.flashswapLeverage +DA:109,180026 +DA:110,180026 +FN:124,UniswapFlashswapHandler._flashswapLeverage +FNDA:210030,UniswapFlashswapHandler._flashswapLeverage +DA:132,210030 +DA:134,210030 +BRDA:134,0,0,46269 +BRDA:134,0,1,163761 +DA:136,46269 +DA:137,46269 +DA:143,163761 +DA:145,163761 +DA:151,163761 +DA:152,163761 +DA:155,163761 +BRDA:155,1,0,4 +BRDA:155,1,1,163757 +DA:156,4 +FN:177,UniswapFlashswapHandler.flashswapDeleverage +FNDA:120022,UniswapFlashswapHandler.flashswapDeleverage +DA:186,120016 +BRDA:186,2,0,46812 +BRDA:186,2,1,120016 +DA:187,46812 +DA:190,120016 +BRDA:190,3,0,93843 +BRDA:190,3,1,120012 +DA:193,93843 +DA:195,93843 +DA:196,93843 +DA:198,93843 +DA:200,93843 +BRDA:200,4,0,4 +BRDA:200,4,1,93839 +FN:212,UniswapFlashswapHandler._initiateFlashSwap +FNDA:257604,UniswapFlashswapHandler._initiateFlashSwap +DA:222,257604 +BRDA:222,5,0,- +BRDA:222,5,1,257604 +DA:223,0 +DA:226,257604 +DA:234,257604 +DA:235,257604 +DA:240,257604 +BRDA:240,6,0,- +BRDA:240,6,1,257604 +FN:257,UniswapFlashswapHandler.uniswapV3SwapCallback +FNDA:257612,UniswapFlashswapHandler.uniswapV3SwapCallback +DA:258,257612 +BRDA:258,7,0,4 +BRDA:258,7,1,257608 +DA:261,257608 +BRDA:261,8,0,4 +BRDA:261,8,1,257604 +DA:262,257604 +DA:264,257604 +DA:265,257604 +DA:269,257604 +BRDA:269,9,0,179544 +BRDA:269,9,1,257604 +DA:270,179544 +DA:271,179544 +DA:274,257604 +DA:275,257604 +BRDA:275,10,0,163761 +BRDA:275,10,1,93843 +DA:276,163761 +DA:282,163761 +DA:286,93843 +DA:290,93843 +DA:293,257604 +FNF:5 +FNH:5 +LF:41 +LH:40 +BRF:22 +BRH:20 +end_of_record +TN: +SF:src/join/GemJoin.sol +FN:57,GemJoin.pause +FNDA:12,GemJoin.pause +DA:58,9 +FN:65,GemJoin.unpause +FNDA:6,GemJoin.unpause +DA:66,3 +FN:75,GemJoin.join +FNDA:1261562,GemJoin.join +DA:76,1261562 +BRDA:76,0,0,3 +BRDA:76,0,1,1261559 +DA:78,1261559 +DA:80,1261559 +DA:81,1261559 +FN:90,GemJoin.exit +FNDA:125175,GemJoin.exit +DA:91,125175 +BRDA:91,1,0,3 +BRDA:91,1,1,125172 +DA:93,125172 +DA:95,125172 +DA:96,125172 +FNF:4 +FNH:4 +LF:10 +LH:10 +BRF:4 +BRH:4 +end_of_record +TN: +SF:src/libraries/EtherFiLibrary.sol +FN:34,EtherFiLibrary.getEthAmountInForLstAmountOut +FNDA:0,EtherFiLibrary.getEthAmountInForLstAmountOut +DA:35,0 +BRDA:35,0,0,- +BRDA:35,0,1,- +DA:37,0 +DA:38,0 +DA:40,0 +DA:41,0 +DA:43,0 +DA:46,0 +BRDA:46,1,0,- +BRDA:46,1,1,- +DA:47,0 +DA:49,0 +BRDA:49,2,0,- +BRDA:49,2,1,- +DA:50,0 +DA:54,0 +FN:63,EtherFiLibrary.getLstAmountOutForEthAmountIn +FNDA:0,EtherFiLibrary.getLstAmountOutForEthAmountIn +DA:64,0 +DA:65,0 +DA:67,0 +DA:68,0 +DA:70,0 +FN:83,EtherFiLibrary._getLstAmountOutForEthAmountIn +FNDA:0,EtherFiLibrary._getLstAmountOutForEthAmountIn +DA:92,0 +DA:93,0 +DA:94,0 +BRDA:94,3,0,- +BRDA:94,3,1,- +DA:96,0 +DA:97,0 +DA:99,0 +FN:109,EtherFiLibrary.depositForLrt +FNDA:0,EtherFiLibrary.depositForLrt +DA:110,0 +DA:111,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:116,0 +FN:128,EtherFiLibrary._sharesForAmount +FNDA:0,EtherFiLibrary._sharesForAmount +DA:137,0 +BRDA:137,4,0,- +BRDA:137,4,1,- +DA:139,0 +FN:151,EtherFiLibrary._amountForShares +FNDA:0,EtherFiLibrary._amountForShares +DA:160,0 +FNF:6 +FNH:0 +LF:31 +LH:0 +BRF:10 +BRH:0 +end_of_record +TN: +SF:src/libraries/LidoLibrary.sol +FN:25,LidoLibrary.getEthAmountInForLstAmountOut +FNDA:0,LidoLibrary.getEthAmountInForLstAmountOut +DA:26,0 +DA:27,0 +FN:35,LidoLibrary.getLstAmountOutForEthAmountIn +FNDA:0,LidoLibrary.getLstAmountOutForEthAmountIn +DA:37,0 +FN:45,LidoLibrary.depositForLst +FNDA:0,LidoLibrary.depositForLst +DA:46,0 +DA:47,0 +BRDA:47,0,0,- +BRDA:47,0,1,- +DA:49,0 +FNF:3 +FNH:0 +LF:6 +LH:0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:src/libraries/StaderLibrary.sol +FN:23,StaderLibrary.getEthAmountInForLstAmountOut +FNDA:0,StaderLibrary.getEthAmountInForLstAmountOut +DA:31,0 +DA:32,0 +FN:40,StaderLibrary.getLstAmountOutForEthAmountIn +FNDA:0,StaderLibrary.getLstAmountOutForEthAmountIn +DA:48,0 +FN:56,StaderLibrary.depositForLst +FNDA:0,StaderLibrary.depositForLst +DA:57,0 +FN:68,StaderLibrary.depositForLst +FNDA:0,StaderLibrary.depositForLst +DA:76,0 +FNF:4 +FNH:0 +LF:5 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/libraries/SwellLibrary.sol +FN:22,SwellLibrary.getEthAmountInForLstAmountOut +FNDA:0,SwellLibrary.getEthAmountInForLstAmountOut +DA:23,0 +FN:31,SwellLibrary.getLstAmountOutForEthAmountIn +FNDA:0,SwellLibrary.getLstAmountOutForEthAmountIn +DA:33,0 +FN:41,SwellLibrary.depositForLst +FNDA:0,SwellLibrary.depositForLst +DA:42,0 +DA:43,0 +FNF:3 +FNH:0 +LF:4 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/libraries/math/WadRayMath.sol +FN:31,WadRayMath.wadMulDown +FNDA:0,WadRayMath.wadMulDown +DA:32,0 +FN:41,WadRayMath.wadMulUp +FNDA:0,WadRayMath.wadMulUp +DA:42,0 +FN:51,WadRayMath.wadDivDown +FNDA:0,WadRayMath.wadDivDown +DA:52,0 +FN:61,WadRayMath.wadDivUp +FNDA:0,WadRayMath.wadDivUp +DA:62,0 +FN:71,WadRayMath.rayMulDown +FNDA:0,WadRayMath.rayMulDown +DA:72,0 +FN:81,WadRayMath.rayMulUp +FNDA:0,WadRayMath.rayMulUp +DA:82,0 +FN:91,WadRayMath.rayDivDown +FNDA:0,WadRayMath.rayDivDown +DA:92,0 +FN:101,WadRayMath.rayDivUp +FNDA:0,WadRayMath.rayDivUp +DA:102,0 +FN:111,WadRayMath.radMulDown +FNDA:0,WadRayMath.radMulDown +DA:112,0 +FN:121,WadRayMath.radMulUp +FNDA:0,WadRayMath.radMulUp +DA:122,0 +FN:131,WadRayMath.radDivDown +FNDA:0,WadRayMath.radDivDown +DA:132,0 +FN:141,WadRayMath.radDivUp +FNDA:0,WadRayMath.radDivUp +DA:142,0 +FN:153,WadRayMath.scaleUpToWad +FNDA:0,WadRayMath.scaleUpToWad +DA:154,0 +FN:163,WadRayMath.scaleUpToRay +FNDA:0,WadRayMath.scaleUpToRay +DA:164,0 +FN:173,WadRayMath.scaleUpToRad +FNDA:0,WadRayMath.scaleUpToRad +DA:174,0 +FN:183,WadRayMath.scaleDownToWad +FNDA:0,WadRayMath.scaleDownToWad +DA:184,0 +FN:193,WadRayMath.scaleDownToRay +FNDA:0,WadRayMath.scaleDownToRay +DA:194,0 +FN:203,WadRayMath.scaleDownToRad +FNDA:0,WadRayMath.scaleDownToRad +DA:204,0 +FN:213,WadRayMath.scaleUp +FNDA:0,WadRayMath.scaleUp +DA:214,0 +BRDA:214,0,0,- +BRDA:214,0,1,- +DA:215,0 +FN:224,WadRayMath.scaleDown +FNDA:0,WadRayMath.scaleDown +DA:225,0 +BRDA:225,1,0,- +BRDA:225,1,1,- +DA:226,0 +FNF:20 +FNH:0 +LF:22 +LH:0 +BRF:4 +BRH:0 +end_of_record +TN: +SF:src/oracles/reserve/EthXReserveOracle.sol +FN:40,EthXReserveOracle._getProtocolExchangeRate +FNDA:22,EthXReserveOracle._getProtocolExchangeRate +DA:41,22 +FNF:1 +FNH:1 +LF:1 +LH:1 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/oracles/reserve/ReserveFeed.sol +FN:12,ReserveFeed.setExchangeRate +FNDA:15,ReserveFeed.setExchangeRate +DA:13,15 +FN:16,ReserveFeed.getExchangeRate +FNDA:31,ReserveFeed.getExchangeRate +DA:17,31 +FNF:2 +FNH:2 +LF:2 +LH:2 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/oracles/reserve/ReserveOracle.sol +FN:90,ReserveOracle.getProtocolExchangeRate +FNDA:5,ReserveOracle.getProtocolExchangeRate +DA:91,5 +FN:99,ReserveOracle._aggregate +FNDA:26,ReserveOracle._aggregate +DA:100,26 +BRDA:100,0,0,21 +BRDA:100,0,1,5 +DA:101,21 +DA:102,5 +BRDA:102,1,0,- +BRDA:102,1,1,1 +DA:103,1 +DA:104,4 +BRDA:104,2,0,- +BRDA:104,2,1,2 +DA:105,2 +DA:106,2 +DA:107,2 +DA:108,2 +BRDA:108,3,0,- +BRDA:108,3,1,2 +DA:109,2 +DA:110,2 +DA:111,2 +DA:112,2 +FN:122,ReserveOracle._bound +FNDA:26,ReserveOracle._bound +DA:123,26 +BRDA:123,4,0,- +BRDA:123,4,1,26 +DA:125,26 +FN:132,ReserveOracle._initializeExchangeRate +FNDA:0,ReserveOracle._initializeExchangeRate +DA:133,0 +DA:134,0 +BRDA:134,5,0,- +BRDA:134,5,1,- +DA:135,0 +DA:138,0 +FN:147,ReserveOracle.updateExchangeRate +FNDA:30,ReserveOracle.updateExchangeRate +DA:148,30 +BRDA:148,6,0,4 +BRDA:148,6,1,26 +DA:150,26 +DA:152,26 +DA:153,26 +DA:155,26 +DA:156,26 +DA:158,26 +DA:160,26 +FNF:5 +FNH:4 +LF:28 +LH:24 +BRF:14 +BRH:8 +end_of_record +TN: +SF:src/oracles/reserve/SwEthReserveOracle.sol +FN:40,SwEthReserveOracle._getProtocolExchangeRate +FNDA:0,SwEthReserveOracle._getProtocolExchangeRate +DA:41,0 +FNF:1 +FNH:0 +LF:1 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/oracles/reserve/WeEthWstEthReserveOracle.sol +FN:44,WeEthWstEthReserveOracle._getProtocolExchangeRate +FNDA:9,WeEthWstEthReserveOracle._getProtocolExchangeRate +DA:47,9 +FNF:1 +FNH:1 +LF:1 +LH:1 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/oracles/reserve/WstEthReserveOracle.sol +FN:48,WstEthReserveOracle._getProtocolExchangeRate +FNDA:0,WstEthReserveOracle._getProtocolExchangeRate +DA:49,0 +FNF:1 +FNH:0 +LF:1 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/oracles/spot/EthXSpotOracle.sol +FN:55,EthXSpotOracle.getPrice +FNDA:2,EthXSpotOracle.getPrice +DA:58,4 +DA:60,4 +DA:63,4 +DA:64,4 +DA:67,4 +FNF:1 +FNH:1 +LF:5 +LH:5 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/oracles/spot/SpotOracle.sol +FN:64,SpotOracle.getSpot +FNDA:2979857,SpotOracle.getSpot +DA:65,2979857 +DA:66,2979857 +DA:69,2979857 +DA:71,2979857 +FNF:1 +FNH:1 +LF:4 +LH:4 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/oracles/spot/SwEthSpotOracle.sol +FN:52,SwEthSpotOracle.getPrice +FNDA:2,SwEthSpotOracle.getPrice +DA:53,4 +DA:54,4 +DA:56,4 +DA:57,4 +FN:64,SwEthSpotOracle._getPriceInWadFromSqrtPriceX96 +FNDA:4,SwEthSpotOracle._getPriceInWadFromSqrtPriceX96 +DA:65,4 +FNF:2 +FNH:2 +LF:5 +LH:5 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/oracles/spot/WeEthWstEthSpotOracle.sol +FN:51,WeEthWstEthSpotOracle.getPrice +FNDA:5,WeEthWstEthSpotOracle.getPrice +DA:52,18 +DA:54,18 +DA:58,18 +DA:59,16 +BRDA:57,0,0,2 +BRDA:57,0,1,16 +DA:61,2 +DA:64,16 +DA:65,16 +DA:67,16 +DA:68,16 +FNF:1 +FNH:1 +LF:9 +LH:9 +BRF:2 +BRH:2 +end_of_record +TN: +SF:src/oracles/spot/WstEthSpotOracle.sol +FN:50,WstEthSpotOracle.getPrice +FNDA:3,WstEthSpotOracle.getPrice +DA:52,5 +DA:53,5 +DA:55,5 +FNF:1 +FNH:1 +LF:3 +LH:3 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/periphery/IonRegistry.sol +FN:19,IonRegistry.setGemJoin +FNDA:0,IonRegistry.setGemJoin +DA:20,0 +FN:23,IonRegistry.setDepositContract +FNDA:0,IonRegistry.setDepositContract +DA:24,0 +FNF:2 +FNH:0 +LF:2 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/reward/RewardModule.sol +FN:90,RewardModule._getRewardModuleStorage +FNDA:14997243,RewardModule._getRewardModuleStorage +DA:92,14997243 +FN:96,RewardModule._initialize +FNDA:403,RewardModule._initialize +DA:106,403 +BRDA:106,0,0,3 +BRDA:106,0,1,400 +DA:107,400 +BRDA:107,1,0,3 +BRDA:107,1,1,397 +DA:109,397 +DA:111,397 +DA:112,397 +DA:113,397 +DA:114,397 +DA:115,397 +DA:116,397 +DA:118,397 +FN:127,RewardModule._burn +FNDA:72318,RewardModule._burn +DA:128,72318 +DA:130,72318 +DA:131,72318 +DA:133,72318 +BRDA:133,2,0,- +BRDA:133,2,1,72318 +DA:134,72318 +DA:136,62315 +DA:138,62315 +DA:140,62315 +FN:148,RewardModule._burnNormalized +FNDA:72318,RewardModule._burnNormalized +DA:149,72318 +DA:151,72318 +BRDA:151,3,0,10002 +BRDA:151,3,1,62316 +DA:153,62316 +DA:154,62316 +BRDA:154,4,0,1 +BRDA:154,4,1,62315 +DA:157,62315 +DA:160,62315 +FN:169,RewardModule._mint +FNDA:190835,RewardModule._mint +DA:170,190835 +DA:172,190835 +DA:173,190835 +DA:174,190835 +BRDA:174,5,0,2 +BRDA:174,5,1,190833 +DA:175,190833 +DA:177,180832 +DA:179,180832 +DA:181,180832 +FN:189,RewardModule._mintNormalized +FNDA:319075,RewardModule._mintNormalized +DA:190,319075 +BRDA:190,6,0,10001 +BRDA:190,6,1,309074 +DA:192,309074 +DA:194,309074 +DA:196,309074 +FN:203,RewardModule._mintToTreasury +FNDA:2760982,RewardModule._mintToTreasury +DA:204,2760982 +BRDA:204,7,0,128242 +BRDA:204,7,1,2760982 +DA:206,128242 +DA:208,128242 +DA:209,128242 +DA:216,128242 +DA:218,128242 +DA:219,128242 +FN:222,RewardModule._setSupplyFactor +FNDA:2831501,RewardModule._setSupplyFactor +DA:223,2831501 +DA:224,2831501 +FN:231,RewardModule.updateTreasury +FNDA:3,RewardModule.updateTreasury +DA:232,2 +BRDA:232,8,0,1 +BRDA:232,8,1,1 +DA:234,1 +DA:235,1 +DA:237,1 +FN:245,RewardModule.underlying +FNDA:20256,RewardModule.underlying +DA:246,1009694 +DA:247,1009694 +FN:253,RewardModule.decimals +FNDA:45,RewardModule.decimals +DA:254,45 +DA:255,45 +FN:262,RewardModule.balanceOf +FNDA:312948,RewardModule.balanceOf +DA:263,312948 +DA:265,312948 +DA:267,312948 +FN:274,RewardModule.normalizedBalanceOf +FNDA:40401,RewardModule.normalizedBalanceOf +DA:275,40401 +DA:276,40401 +FN:282,RewardModule.name +FNDA:45,RewardModule.name +DA:283,45 +DA:284,45 +FN:290,RewardModule.symbol +FNDA:45,RewardModule.symbol +DA:291,45 +DA:292,45 +FN:298,RewardModule.treasury +FNDA:46,RewardModule.treasury +DA:299,46 +DA:300,46 +FN:303,RewardModule.totalSupplyUnaccrued +FNDA:0,RewardModule.totalSupplyUnaccrued +DA:304,6323895 +DA:306,6323895 +DA:308,6323895 +BRDA:308,9,0,280132 +BRDA:308,9,1,6043763 +DA:309,280132 +DA:312,6043763 +FN:318,RewardModule.totalSupply +FNDA:51033,RewardModule.totalSupply +DA:319,171552 +DA:321,171552 +DA:323,171552 +BRDA:323,10,0,30006 +BRDA:323,10,1,141546 +DA:324,30006 +DA:327,141546 +DA:329,141546 +FN:332,RewardModule.normalizedTotalSupplyUnaccrued +FNDA:0,RewardModule.normalizedTotalSupplyUnaccrued +DA:333,586339 +DA:334,586339 +FN:340,RewardModule.normalizedTotalSupply +FNDA:6290,RewardModule.normalizedTotalSupply +DA:341,6290 +DA:343,6290 +DA:345,6290 +DA:346,6290 +DA:348,6290 +FN:351,RewardModule.supplyFactorUnaccrued +FNDA:2,RewardModule.supplyFactorUnaccrued +DA:352,2760983 +DA:353,2760983 +FN:359,RewardModule.supplyFactor +FNDA:180274,RewardModule.supplyFactor +DA:360,180274 +DA:362,180274 +DA:364,180274 +FNF:22 +FNH:20 +LF:88 +LH:88 +BRF:22 +BRH:21 +end_of_record diff --git a/lib/solarray b/lib/solarray new file mode 160000 index 00000000..a547630f --- /dev/null +++ b/lib/solarray @@ -0,0 +1 @@ +Subproject commit a547630f9bf7837af9e6919d217672afe7abf7f1 diff --git a/remappings.txt b/remappings.txt index 19cc83bd..9e2498ef 100644 --- a/remappings.txt +++ b/remappings.txt @@ -19,3 +19,4 @@ solmate/=lib/forge-safe/lib/solmate/src/ surl/=lib/forge-safe/lib/surl/ v3-core/=lib/v3-core/ v3-periphery/=lib/v3-periphery/contracts/ +solarray/=lib/solarray/src/ diff --git a/test/helpers/IonPoolSharedSetup.sol b/test/helpers/IonPoolSharedSetup.sol index dee3b61a..f5b5c39e 100644 --- a/test/helpers/IonPoolSharedSetup.sol +++ b/test/helpers/IonPoolSharedSetup.sol @@ -12,6 +12,8 @@ import { SpotOracle } from "../../src/oracles/spot/SpotOracle.sol"; import { BaseTestSetup } from "../helpers/BaseTestSetup.sol"; import { YieldOracleSharedSetup } from "../helpers/YieldOracleSharedSetup.sol"; import { ERC20PresetMinterPauser } from "../helpers/ERC20PresetMinterPauser.sol"; +import { YieldOracle } from "../../src/YieldOracle.sol"; +import { Solarray } from "solarray/Solarray.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; @@ -38,7 +40,11 @@ using WadRayMath for uint16; // } contract MockYieldOracle is IYieldOracle { - uint32 APY = 3.45e6; + uint32 immutable APY; + + constructor(uint32 apy) { + APY = apy; + } function apys(uint256) external view returns (uint32) { return APY; @@ -95,7 +101,21 @@ contract MockReserveOracle { } } +struct Config { + uint128[] minimumProfitMargins; + uint128[] minimumKinkRates; + uint16[] reserveFactors; + uint128[] adjustedBaseRates; + uint128[] minimumBaseRates; + uint16[] optimalUtilizationRates; + uint16[] distributionFactors; + uint128[] adjustedAboveKinkSlopes; + uint128[] minimumAboveKinkSlopes; +} + abstract contract IonPoolSharedSetup is BaseTestSetup, YieldOracleSharedSetup { + Config config; + IonPoolExposed ionPool; IonPoolExposed ionPoolImpl; IonRegistry ionRegistry; @@ -157,23 +177,29 @@ abstract contract IonPoolSharedSetup is BaseTestSetup, YieldOracleSharedSetup { uint256 internal wstEthDebtCeiling = 20e45; uint256 internal ethXDebtCeiling = 40e45; uint256 internal swEthDebtCeiling = 40e45; + uint256[] internal debtCeilings = [wstEthDebtCeiling, ethXDebtCeiling, swEthDebtCeiling]; IERC20[] internal collaterals; GemJoin[] internal gemJoins; MockSpotOracle[] internal spotOracles; - uint96[] internal minimumProfitMargins = - [wstEthMinimumProfitMargin, ethXMinimumProfitMargin, swEthMinimumProfitMargin]; - uint16[] internal adjustedReserveFactors = - [wstEthAdjustedReserveFactor, ethXAdjustedReserveFactor, swEthAdjustedReserveFactor]; - uint16[] internal optimalUtilizationRates = - [wstEthOptimalUtilizationRate, ethXOptimalUtilizationRate, swEthOptimalUtilizationRate]; - uint16[] internal distributionFactors = [wstEthDistributionFactor, ethXDistributionFactor, swEthDistributionFactor]; - uint256[] internal debtCeilings = [wstEthDebtCeiling, ethXDebtCeiling, swEthDebtCeiling]; - uint96[] internal adjustedAboveKinkSlopes = - [wstEthAdjustedAboveKinkSlope, ethXAdjustedAboveKinkSlope, swEthAdjustedAboveKinkSlope]; - uint96[] internal minimumAboveKinkSlopes = - [wstEthMinimumAboveKinkSlope, ethXMinimumAboveKinkSlope, swEthMinimumAboveKinkSlope]; + constructor() { + config.minimumProfitMargins = + Solarray.uint128s(wstEthMinimumProfitMargin, ethXMinimumProfitMargin, swEthMinimumProfitMargin); + config.minimumKinkRates = Solarray.uint16s(0, 0, 0); + config.reserveFactors = + Solarray.uint16s(wstEthAdjustedReserveFactor, ethXAdjustedReserveFactor, swEthAdjustedReserveFactor); + config.adjustedBaseRates = Solarray.uint128s(0, 0, 0); + config.minimumBaseRates = Solarray.uint128s(0, 0, 0); + config.optimalUtilizationRates = + Solarray.uint16s(wstEthOptimalUtilizationRate, ethXOptimalUtilizationRate, swEthOptimalUtilizationRate); + config.distributionFactors = + Solarray.uint16s(wstEthDistributionFactor, ethXDistributionFactor, swEthDistributionFactor); + config.adjustedAboveKinkSlopes = + Solarray.uint128s(wstEthAdjustedAboveKinkSlope, ethXAdjustedAboveKinkSlope, swEthAdjustedAboveKinkSlope); + config.minimumAboveKinkSlopes = + Solarray.uint128s(wstEthMinimumAboveKinkSlope, ethXMinimumAboveKinkSlope, swEthMinimumAboveKinkSlope); + } IlkData[] ilkConfigs; @@ -182,34 +208,34 @@ abstract contract IonPoolSharedSetup is BaseTestSetup, YieldOracleSharedSetup { address[] memory depositContracts = _getDepositContracts(); assert( - collaterals.length == adjustedReserveFactors.length - && adjustedReserveFactors.length == optimalUtilizationRates.length - && optimalUtilizationRates.length == distributionFactors.length - && distributionFactors.length == debtCeilings.length + collaterals.length == config.reserveFactors.length + && config.reserveFactors.length == config.optimalUtilizationRates.length + && config.optimalUtilizationRates.length == config.distributionFactors.length + && config.distributionFactors.length == debtCeilings.length ); BaseTestSetup.setUp(); YieldOracleSharedSetup.setUp(); - apyOracle = new MockYieldOracle(); + apyOracle = _getYieldOracle(); uint256 distributionFactorSum; IlkData memory ilkConfig; for (uint256 i = 0; i < collaterals.length; i++) { ilkConfig = IlkData({ - adjustedProfitMargin: minimumProfitMargins[i], - minimumKinkRate: 0, - reserveFactor: adjustedReserveFactors[i], - adjustedBaseRate: 0, - minimumBaseRate: 0, - optimalUtilizationRate: optimalUtilizationRates[i], - distributionFactor: distributionFactors[i], - adjustedAboveKinkSlope: adjustedAboveKinkSlopes[i], - minimumAboveKinkSlope: minimumAboveKinkSlopes[i] + adjustedProfitMargin: uint96(config.minimumProfitMargins[i]), + minimumKinkRate: uint96(config.minimumKinkRates[i]), + reserveFactor: config.reserveFactors[i], + adjustedBaseRate: uint96(config.adjustedBaseRates[i]), + minimumBaseRate: uint96(config.minimumBaseRates[i]), + optimalUtilizationRate: config.optimalUtilizationRates[i], + distributionFactor: config.distributionFactors[i], + adjustedAboveKinkSlope: uint96(config.adjustedAboveKinkSlopes[i]), + minimumAboveKinkSlope: uint96(config.minimumAboveKinkSlopes[i]) }); ilkConfigs.push(ilkConfig); - distributionFactorSum += distributionFactors[i]; + distributionFactorSum += config.distributionFactors[i]; } assert(distributionFactorSum == 1e4); @@ -217,7 +243,7 @@ abstract contract IonPoolSharedSetup is BaseTestSetup, YieldOracleSharedSetup { interestRateModule = new InterestRate(ilkConfigs, apyOracle); // whitelist - whitelist = address(new Whitelist(new bytes32[](0), bytes32(0))); + whitelist = address(_getWhitelist()); // Instantiate upgradeable IonPool ProxyAdmin ionProxyAdmin = new ProxyAdmin(address(this)); @@ -246,11 +272,10 @@ abstract contract IonPoolSharedSetup is BaseTestSetup, YieldOracleSharedSetup { for (uint8 i = 0; i < collaterals.length; i++) { ionPool.initializeIlk(address(collaterals[i])); - MockReserveOracle reserveOracle = new MockReserveOracle(EXCHANGE_RATE); - MockSpotOracle spotOracle = new MockSpotOracle(LTV, address(reserveOracle), PRICE); - spotOracles.push(spotOracle); + SpotOracle spotOracle = _getSpotOracle(); + spotOracles.push(MockSpotOracle(address(spotOracle))); ionPool.updateIlkSpot(i, spotOracle); - ionPool.updateIlkDebtCeiling(i, debtCeilings[i]); + ionPool.updateIlkDebtCeiling(i, _getDebtCeiling(i)); gemJoins.push(new GemJoin(ionPool, collaterals[i], i, address(this))); @@ -308,17 +333,17 @@ abstract contract IonPoolSharedSetup is BaseTestSetup, YieldOracleSharedSetup { // assertEq(reserveFactor, adjustedReserveFactors[i].scaleUpToRay(4)); IlkData memory ilkConfig = interestRateModule.unpackCollateralConfig(i); - assertEq(ilkConfig.adjustedProfitMargin, minimumProfitMargins[i], "minimum profit margin"); - assertEq(ilkConfig.minimumKinkRate, 0, "minimum kink rate"); + assertEq(ilkConfig.adjustedProfitMargin, config.minimumProfitMargins[i], "minimum profit margin"); + assertEq(ilkConfig.minimumKinkRate, config.minimumKinkRates[i], "minimum kink rate"); - assertEq(ilkConfig.reserveFactor, adjustedReserveFactors[i], "reserve factor"); - assertEq(ilkConfig.adjustedBaseRate, 0, "adjusted base rate"); - assertEq(ilkConfig.minimumBaseRate, 0, "minimum base rate"); - assertEq(ilkConfig.optimalUtilizationRate, optimalUtilizationRates[i], "optimal utilization rate"); - assertEq(ilkConfig.distributionFactor, distributionFactors[i], "distribution factor"); + assertEq(ilkConfig.reserveFactor, config.reserveFactors[i], "reserve factor"); + assertEq(ilkConfig.adjustedBaseRate, config.adjustedBaseRates[i], "adjusted base rate"); + assertEq(ilkConfig.minimumBaseRate, config.minimumBaseRates[i], "minimum base rate"); + assertEq(ilkConfig.optimalUtilizationRate, config.optimalUtilizationRates[i], "optimal utilization rate"); + assertEq(ilkConfig.distributionFactor, config.distributionFactors[i], "distribution factor"); - assertEq(ilkConfig.adjustedAboveKinkSlope, adjustedAboveKinkSlopes[i], "adjusted above kink slope"); - assertEq(ilkConfig.minimumAboveKinkSlope, minimumAboveKinkSlopes[i], "minimum above kink slope"); + assertEq(ilkConfig.adjustedAboveKinkSlope, config.adjustedAboveKinkSlopes[i], "adjusted above kink slope"); + assertEq(ilkConfig.minimumAboveKinkSlope, config.minimumAboveKinkSlopes[i], "minimum above kink slope"); } assertEq(interestRateModule.COLLATERAL_COUNT(), collaterals.length, "collateral count"); @@ -336,6 +361,18 @@ abstract contract IonPoolSharedSetup is BaseTestSetup, YieldOracleSharedSetup { _collaterals[2] = IERC20(address(swEth)); } + function _getYieldOracle() internal virtual returns (IYieldOracle) { + return new MockYieldOracle(3.45e6); + } + + function _getSpotOracle() internal virtual returns (SpotOracle) { + return new MockSpotOracle(LTV, address(new MockReserveOracle(EXCHANGE_RATE)), PRICE); + } + + function _getWhitelist() internal virtual returns (Whitelist) { + return new Whitelist(new bytes32[](0), bytes32(0)); + } + function _getSpot() internal view virtual returns (uint256) { return PRICE * LTV / WAD; } diff --git a/test/helpers/MockIonPool.sol b/test/helpers/MockIonPool.sol index ee2b8c0f..3ad41f73 100644 --- a/test/helpers/MockIonPool.sol +++ b/test/helpers/MockIonPool.sol @@ -2,8 +2,18 @@ pragma solidity 0.8.21; contract MockIonPool { - function paused() external pure returns (bool) { - return false; + bool public paused; + + constructor() { + paused = false; + } + + function pause() external { + paused = true; + } + + function unpause() external { + paused = false; } function accrueInterest() external returns (uint256) { diff --git a/test/helpers/YieldOracleSharedSetup.sol b/test/helpers/YieldOracleSharedSetup.sol index ce0aa7ad..eb748149 100644 --- a/test/helpers/YieldOracleSharedSetup.sol +++ b/test/helpers/YieldOracleSharedSetup.sol @@ -72,6 +72,8 @@ abstract contract YieldOracleSharedSetup is Test { MockStader staderOracle; MockSwell swellOracle; + IonPool mockIonPool; + uint64[ILK_COUNT][LOOK_BACK] historicalExchangeRatesInitial; function setUp() public virtual { @@ -93,7 +95,7 @@ abstract contract YieldOracleSharedSetup is Test { historicalExchangeRatesInitial[i] = baseRates; } - IonPool mockIonPool = IonPool(address(new MockIonPool())); + mockIonPool = IonPool(address(new MockIonPool())); oracle = new YieldOracle( historicalExchangeRatesInitial, diff --git a/test/helpers/weETH/WeEthIonHandlerForkBase.sol b/test/helpers/weETH/WeEthIonHandlerForkBase.sol index e185bb4a..c666314d 100644 --- a/test/helpers/weETH/WeEthIonHandlerForkBase.sol +++ b/test/helpers/weETH/WeEthIonHandlerForkBase.sol @@ -24,15 +24,15 @@ using WadRayMath for uint256; abstract contract WeEthIonHandler_ForkBase is IonHandler_ForkBase { function setUp() public virtual override { for (uint256 i = 0; i < 2; i++) { - minimumProfitMargins.pop(); - adjustedReserveFactors.pop(); - optimalUtilizationRates.pop(); - distributionFactors.pop(); + config.minimumProfitMargins.pop(); + config.reserveFactors.pop(); + config.optimalUtilizationRates.pop(); + config.distributionFactors.pop(); debtCeilings.pop(); - adjustedAboveKinkSlopes.pop(); - minimumAboveKinkSlopes.pop(); + config.adjustedAboveKinkSlopes.pop(); + config.minimumAboveKinkSlopes.pop(); } - distributionFactors[0] = 1e4; + config.distributionFactors[0] = 1e4; if (forkBlock == 0) vm.createSelectFork(vm.envString("MAINNET_ARCHIVE_RPC_URL")); else vm.createSelectFork(vm.envString("MAINNET_ARCHIVE_RPC_URL"), forkBlock); diff --git a/test/helpers/weETH/WeEthIonPoolSharedSetup.sol b/test/helpers/weETH/WeEthIonPoolSharedSetup.sol index f1d2c6ca..125f4748 100644 --- a/test/helpers/weETH/WeEthIonPoolSharedSetup.sol +++ b/test/helpers/weETH/WeEthIonPoolSharedSetup.sol @@ -11,15 +11,16 @@ import { safeconsole as console } from "forge-std/safeconsole.sol"; abstract contract WeEthIonPoolSharedSetup is IonPoolSharedSetup { function setUp() public virtual override { for (uint256 i = 0; i < 2; i++) { - minimumProfitMargins.pop(); - adjustedReserveFactors.pop(); - optimalUtilizationRates.pop(); - distributionFactors.pop(); + config.minimumProfitMargins.pop(); + config.reserveFactors.pop(); + config.optimalUtilizationRates.pop(); + config.distributionFactors.pop(); debtCeilings.pop(); - adjustedAboveKinkSlopes.pop(); - minimumAboveKinkSlopes.pop(); + config.adjustedAboveKinkSlopes.pop(); + config.minimumAboveKinkSlopes.pop(); } - distributionFactors[0] = 1e4; + config.distributionFactors[0] = 1e4; + super.setUp(); } diff --git a/test/integration/concrete/WeEthIonPool.t.sol b/test/integration/concrete/WeEthIonPool.t.sol new file mode 100644 index 00000000..fa081e40 --- /dev/null +++ b/test/integration/concrete/WeEthIonPool.t.sol @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { YieldOracle } from "../../../src/YieldOracle.sol"; +import { WeEthIonPoolSharedSetup } from "../../helpers/weETH/WeEthIonPoolSharedSetup.sol"; +import { Whitelist } from "../../../src/Whitelist.sol"; +import { WSTETH_ADDRESS, WEETH_ADDRESS, EETH_ADDRESS } from "../../../src/Constants.sol"; +import { IWstEth, IWeEth } from "../../../src/interfaces/ProviderInterfaces.sol"; +import { LidoLibrary } from "../../../src/libraries/LidoLibrary.sol"; +import { EtherFiLibrary } from "../../../src/libraries/EtherFiLibrary.sol"; +import { SpotOracle } from "../../../src/oracles/spot/SpotOracle.sol"; +import { WeEthWstEthReserveOracle } from "../../../src/oracles/reserve/WeEthWstEthReserveOracle.sol"; +import { WeEthWstEthSpotOracle } from "../../../src/oracles/spot/WeEthWstEthSpotOracle.sol"; + +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; + +using LidoLibrary for IWstEth; +using EtherFiLibrary for IWeEth; +using Math for uint256; + +contract WeEthIonPool_IntegrationTest is WeEthIonPoolSharedSetup { + // generate merkle root + // ["0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496"], + // ["0x2222222222222222222222222222222222222222"], + // => 0xb51a382d5bcb4cd5fe50a7d4d8abaf056ac1a6961cf654ec4f53a570ab75a30b + + bytes32 borrowerWhitelistRoot = 0x846dfddafc70174f2089edda6408bf9dd643c19ee06ff11643b614f0e277d6e3; + + bytes32[][] borrowerProofs = [ + [bytes32(0x708e7cb9a75ffb24191120fba1c3001faa9078147150c6f2747569edbadee751)], + [bytes32(0xa6e6806303186f9c20e1af933c7efa83d98470acf93a10fb8da8b1d9c2873640)] + ]; + + // generate merkle root + // ["0x0000000000000000000000000000000000000001"], + // ["0x0000000000000000000000000000000000000002"], + // ["0x0000000000000000000000000000000000000003"], + // ["0x0000000000000000000000000000000000000004"], + // ["0x0000000000000000000000000000000000000005"], + // => 0x21abd2f655ded75d91fbd5e0b1ad35171a675fd315a077efa7f2d555a26e7094 + + bytes32 lenderRoot = 0x21abd2f655ded75d91fbd5e0b1ad35171a675fd315a077efa7f2d555a26e7094; + + // Proofs for address(1) and address(3) + bytes32[][] lenderProofs = [ + [ + bytes32(0x2584db4a68aa8b172f70bc04e2e74541617c003374de6eb4b295e823e5beab01), + bytes32(0xc949c2dc5da2bd9a4f5ae27532dfbb3551487bed50825cd099ff5d0a8d613ab5) + ], + [ + bytes32(0xb5d9d894133a730aa651ef62d26b0ffa846233c74177a591a4a896adfda97d22), + bytes32(0xc949c2dc5da2bd9a4f5ae27532dfbb3551487bed50825cd099ff5d0a8d613ab5) + ] + ]; + + uint256 internal constant INITIAL_ETHER_BALANCE = 10_000e18; + uint256 internal constant LST_ETHER_DEPOSIT_AMOUNT = 5000e18; + + address lenderA = address(1); + address lenderB = address(3); + + address borrowerA = address(this); + address borrowerB = address(0x2222222222222222222222222222222222222222); + + WeEthWstEthReserveOracle reserveOracle; + WeEthWstEthSpotOracle spotOracle; + + uint256 internal constant DEBT_CEILING = 10_000e45; + + function setUp() public virtual override { + vm.createSelectFork(vm.envString("MAINNET_RPC_URL")); + + uint256 maxChange = 0.03e27; + reserveOracle = new WeEthWstEthReserveOracle(0, new address[](3), 0, maxChange); + + uint256 maxTimeFromLastUpdate = 1 days; + uint256 ltv = 0.8e27; + spotOracle = new WeEthWstEthSpotOracle(ltv, address(reserveOracle), maxTimeFromLastUpdate); + + config.minimumProfitMargins[0] = 0; + config.minimumKinkRates[0] = 4_062_570_058_138_700_000; + config.reserveFactors[0] = 0; + config.adjustedBaseRates[0] = 0; + config.minimumBaseRates[0] = 1_580_630_071_273_960_000; + config.optimalUtilizationRates[0] = 8500; + config.adjustedAboveKinkSlopes[0] = 0; + config.minimumAboveKinkSlopes[0] = 23_863_999_665_252_300_000; + + super.setUp(); + + ionPool.updateSupplyCap(10_000 ether); + + vm.deal(lenderA, INITIAL_ETHER_BALANCE); + vm.prank(lenderA); + WSTETH_ADDRESS.depositForLst(LST_ETHER_DEPOSIT_AMOUNT); + + vm.deal(lenderB, INITIAL_ETHER_BALANCE); + vm.prank(lenderB); + WSTETH_ADDRESS.depositForLst(LST_ETHER_DEPOSIT_AMOUNT); + + // For borrowerA (address(this)) + EETH_ADDRESS.approve(address(WEETH_ADDRESS), type(uint256).max); + WEETH_ADDRESS.depositForLrt(LST_ETHER_DEPOSIT_AMOUNT); + + vm.deal(borrowerB, INITIAL_ETHER_BALANCE); + vm.startPrank(borrowerB); + EETH_ADDRESS.approve(address(WEETH_ADDRESS), type(uint256).max); + WEETH_ADDRESS.depositForLrt(LST_ETHER_DEPOSIT_AMOUNT); + vm.stopPrank(); + } + + function test_LenderAndBorrowerUserFlow() public { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ACTION 1 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + vm.expectRevert(abi.encodeWithSelector(Whitelist.NotWhitelistedLender.selector, borrowerA)); + ionPool.supply(borrowerA, 1, new bytes32[](0)); + + uint256 lenderAFirstSupplyAmount = 500e18; + + vm.startPrank(lenderA); + WSTETH_ADDRESS.approve(address(ionPool), type(uint256).max); + ionPool.supply(lenderA, lenderAFirstSupplyAmount, lenderProofs[0]); + vm.stopPrank(); + + assertEq(ionPool.balanceOf(lenderA), lenderAFirstSupplyAmount, "lender balance after 1st supply"); + assertEq(ionPool.weth(), lenderAFirstSupplyAmount, "liquidity after 1st supply"); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ACTION 2 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + uint256 borrowerADepositAmount1 = 700e18; + uint256 borrowerABorrowAmount1 = 350e18; + + // BorrowerA (address(this)) + WEETH_ADDRESS.approve(address(gemJoins[0]), type(uint256).max); + gemJoins[0].join(borrowerA, borrowerADepositAmount1); + ionPool.depositCollateral(0, borrowerA, borrowerA, borrowerADepositAmount1, borrowerProofs[0]); + ionPool.borrow(0, borrowerA, borrowerA, borrowerABorrowAmount1, borrowerProofs[0]); + + assertEq( + WSTETH_ADDRESS.balanceOf(borrowerA), borrowerABorrowAmount1, "borrowerA wstETH balance after 1st borrow" + ); + assertEq( + ionPool.normalizedDebt(0, borrowerA).mulDiv(ionPool.rate(0), 1e27, Math.Rounding.Ceil), + borrowerABorrowAmount1, + "borrowerA debt after 1st borrow" + ); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ACTION 3 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + vm.warp(block.timestamp + 172); + + assertGe( + ionPool.normalizedDebt(0, borrowerA).mulDiv(ionPool.rate(0), 1e27, Math.Rounding.Ceil), + borrowerABorrowAmount1, + "borrowerA debt should increase with time passing" + ); + + uint256 lenderBFirstSupplyAmount = 100e18; + + vm.startPrank(lenderB); + WSTETH_ADDRESS.approve(address(ionPool), type(uint256).max); + ionPool.supply(lenderB, lenderBFirstSupplyAmount, lenderProofs[1]); + vm.stopPrank(); + + uint256 roundingError = ionPool.supplyFactor() / 1e27; + + assertApproxEqAbs( + ionPool.balanceOf(lenderB), lenderBFirstSupplyAmount, roundingError, "lenderB balance after 1st supply" + ); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ACTION 4 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + vm.warp(block.timestamp + 597); + + uint256 borrowerBDepositAmount1 = 500e18; + uint256 borrowerBBorrowAmount1 = 200e18; + uint256 normalizedBorrowerBBorrowAmount1 = + borrowerBBorrowAmount1.mulDiv(1e27, ionPool.rate(0), Math.Rounding.Ceil); + + vm.startPrank(borrowerB); + WEETH_ADDRESS.approve(address(gemJoins[0]), type(uint256).max); + gemJoins[0].join(borrowerB, borrowerADepositAmount1); + ionPool.depositCollateral(0, borrowerB, borrowerB, borrowerBDepositAmount1, borrowerProofs[1]); + ionPool.borrow(0, borrowerB, borrowerB, normalizedBorrowerBBorrowAmount1, borrowerProofs[1]); + vm.stopPrank(); + + assertEq( + ionPool.normalizedDebt(0, borrowerB), + normalizedBorrowerBBorrowAmount1, + "borrowerB normalized debt after 1st borrow" + ); + assertEq( + WSTETH_ADDRESS.balanceOf(borrowerB), borrowerBBorrowAmount1, "borrowerB wstETH balance after 1st borrow" + ); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ACTION 5 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + vm.warp(block.timestamp + 56); + + // Not enough liquidity to service this withdrawal + uint256 lender1WithdrawAmountFail = 100e18; + + // Should underflow + vm.expectRevert(); + vm.startPrank(lenderA); + ionPool.withdraw(lenderA, lender1WithdrawAmountFail); + + uint256 lenderABalanceBefore = ionPool.balanceOf(lenderA); + + uint256 lender1WithdrawAmount = 10e18; + ionPool.withdraw(lenderA, lender1WithdrawAmount); + vm.stopPrank(); + + assertEq( + ionPool.balanceOf(lenderA), + lenderABalanceBefore - lender1WithdrawAmount, + "lenderA balance after 1st withdrawal" + ); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ACTION 6 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + vm.warp(block.timestamp + 812); + + uint256 borrowerBRepayAmount1 = 100e18; + + uint256 normalizedDebtBeforeRepay = ionPool.normalizedDebt(0, borrowerB); + + vm.startPrank(borrowerB); + WSTETH_ADDRESS.approve(address(ionPool), type(uint256).max); + ionPool.repay(0, borrowerB, borrowerB, borrowerBRepayAmount1); + + assertEq( + ionPool.normalizedDebt(0, borrowerB), + normalizedDebtBeforeRepay - borrowerBRepayAmount1, + "borrowerB normalized debt after 1st repayment" + ); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ACTION 7 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + vm.warp(block.timestamp + 329); + + uint256 borrowerBRepayOnBehalfOfAAmount = 30e18; + + uint256 normalizedDebtABefore = ionPool.normalizedDebt(0, borrowerA); + + ionPool.repay(0, borrowerA, borrowerB, borrowerBRepayOnBehalfOfAAmount); + vm.stopPrank(); + + assertEq( + ionPool.normalizedDebt(0, borrowerA), + normalizedDebtABefore - borrowerBRepayOnBehalfOfAAmount, + "borrowerA normalized debt after repayment from B on behalf of borrowerA" + ); + } + + function _getSpot() internal view override returns (uint256) { + return spotOracle.getSpot(); + } + + function _getDebtCeiling(uint8) internal pure override returns (uint256) { + return DEBT_CEILING; + } + + function _getSpotOracle() internal view override returns (SpotOracle) { + return spotOracle; + } + + function _getWhitelist() internal override returns (Whitelist) { + bytes32[] memory borrowerWhitelist = new bytes32[](1); + borrowerWhitelist[0] = borrowerWhitelistRoot; + + return new Whitelist(borrowerWhitelist, lenderRoot); + } +} diff --git a/test/invariant/IonPool/ActorManager.t.sol b/test/invariant/IonPool/ActorManager.t.sol index f4962252..91faabb7 100644 --- a/test/invariant/IonPool/ActorManager.t.sol +++ b/test/invariant/IonPool/ActorManager.t.sol @@ -190,7 +190,8 @@ contract IonPool_InvariantTest is IonPoolSharedSetup { } for (uint256 i = 0; i < AMOUNT_LENDERS; i++) { - LenderHandler lender = new LenderHandler(ionPool, ionRegistry, underlying, distributionFactors, log, report); + LenderHandler lender = + new LenderHandler(ionPool, ionRegistry, underlying, config.distributionFactors, log, report); lenders.push(lender); underlying.grantRole(underlying.MINTER_ROLE(), address(lender)); @@ -200,7 +201,7 @@ contract IonPool_InvariantTest is IonPoolSharedSetup { for (uint256 i = 0; i < AMOUNT_BORROWERS; i++) { BorrowerHandler borrower = new BorrowerHandler( - ionPool, ionRegistry, underlying, mintableCollaterals, distributionFactors, log, report + ionPool, ionRegistry, underlying, mintableCollaterals, config.distributionFactors, log, report ); borrowers.push(borrower); for (uint8 j = 0; j < collaterals.length; j++) { diff --git a/test/unit/concrete/YieldOracle.t.sol b/test/unit/concrete/YieldOracle.t.sol index 0a508b1f..08f5c5de 100644 --- a/test/unit/concrete/YieldOracle.t.sol +++ b/test/unit/concrete/YieldOracle.t.sol @@ -39,6 +39,13 @@ contract YieldOracle_UnitTest is YieldOracleSharedSetup { } } + function test_UpdateWhenIonPoolPaused() external { + vm.warp(block.timestamp + 1 days); + + mockIonPool.pause(); + oracle.updateAll(); + } + function test_UpdatingWithChangingExchangeRates() external { uint256 increaseInExchangeRate = 0.072935829352e18; uint256 amountOfUpdatesToTest = 10;