Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

M-04 Fix [PAG] #93

Merged
merged 4 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/InterestRate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,13 @@ contract InterestRate {
if (distributionFactor == 0) {
return (ilkData.minimumKinkRate, ilkData.reserveFactor.scaleUpToRay(4));
}

// If the `totalEthSupply` is small enough to truncate to zero, then
// treat the utilization as zero.
uint256 totalEthSupplyScaled = totalEthSupply.wadMulDown(distributionFactor.scaleUpToWad(4));

// [RAD] / [WAD] = [RAY]
uint256 utilizationRate =
totalEthSupply == 0 ? 0 : totalIlkDebt / (totalEthSupply.wadMulDown(distributionFactor.scaleUpToWad(4)));
uint256 utilizationRate = totalEthSupplyScaled == 0 ? 0 : totalIlkDebt / totalEthSupplyScaled;

// Avoid stack too deep
uint256 adjustedBelowKinkSlope;
Expand Down
76 changes: 76 additions & 0 deletions test/unit/concrete/IonPool.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,82 @@ contract IonPool_InterestTest is IonPoolSharedSetup, IIonPoolEvents {
}
}

// If distribution factor is zero, should return
// minimum kink rate.
function test_DivideByZeroWhenDistributionFactorIsZero() public {
IlkData[] memory ilkConfigs = new IlkData[](2);
uint16[] memory distributionFactors = new uint16[](2);
distributionFactors[0] = 0;
distributionFactors[1] = 1e4;

uint96 minimumKinkRate = 4_062_570_058_138_700_000;
for (uint8 i; i != 2; ++i) {
IlkData memory ilkConfig = IlkData({
adjustedProfitMargin: 0,
minimumKinkRate: minimumKinkRate,
reserveFactor: 0,
adjustedBaseRate: 0,
minimumBaseRate: 0,
optimalUtilizationRate: 9000,
distributionFactor: distributionFactors[i],
adjustedAboveKinkSlope: 0,
minimumAboveKinkSlope: 0
});
ilkConfigs[i] = ilkConfig;
}

interestRateModule = new InterestRate(ilkConfigs, apyOracle);

vm.warp(block.timestamp + 1 days);

(uint256 zeroDistFactorBorrowRate,) = interestRateModule.calculateInterestRate(0, 10e45, 100e18); // 10%
// utilization
assertEq(zeroDistFactorBorrowRate, minimumKinkRate, "borrow rate should be minimum kink rate");

(uint256 nonZeroDistFactorBorrowRate,) = interestRateModule.calculateInterestRate(1, 100e45, 100e18); // 90%
// utilization
assertApproxEqAbs(
nonZeroDistFactorBorrowRate, minimumKinkRate, 1, "borrow rate at any util should be minimum kink rate"
);
}

// If scaling total eth supply with distribution factor truncates to zero,
// should return minimum base rate.
function test_DivideByZeroWhenTotalEthSupplyIsSmall() public {
IlkData[] memory ilkConfigs = new IlkData[](2);
uint16[] memory distributionFactors = new uint16[](2);
distributionFactors[0] = 0.5e4;
distributionFactors[1] = 0.5e4;

uint96 minimumKinkRate = 4_062_570_058_138_700_000;
uint96 minimumBaseRate = 1_580_630_071_273_960_000;
for (uint8 i; i != 2; ++i) {
IlkData memory ilkConfig = IlkData({
adjustedProfitMargin: 0,
minimumKinkRate: minimumKinkRate,
reserveFactor: 0,
adjustedBaseRate: 0,
minimumBaseRate: minimumBaseRate,
optimalUtilizationRate: 9000,
distributionFactor: distributionFactors[i],
adjustedAboveKinkSlope: 0,
minimumAboveKinkSlope: 0
});
ilkConfigs[i] = ilkConfig;
}

interestRateModule = new InterestRate(ilkConfigs, apyOracle);

vm.warp(block.timestamp + 1 days);

(uint256 borrowRate,) = interestRateModule.calculateInterestRate(0, 0, 1); // dust amount of eth supply
assertEq(borrowRate, minimumBaseRate, "borrow rate should be minimum base rate");

(uint256 borrowRateWithoutTruncation,) = interestRateModule.calculateInterestRate(1, 90e45, 100e18); // 90%
// utilization
assertApproxEqAbs(borrowRateWithoutTruncation, minimumKinkRate, 1, "borrow rate without truncation");
}

function test_AccrueInterestWhenPaused() public {
uint256 collateralDepositAmount = 10e18;
uint256 normalizedBorrowAmount = 5e18;
Expand Down
2 changes: 1 addition & 1 deletion test/unit/fuzz/vault/Vault.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { IIonPool } from "./../../../../src/interfaces/IIonPool.sol";
import { IonPoolExposed } from "../../../helpers/IonPoolSharedSetup.sol";
import { VaultSharedSetup } from "../../../helpers/VaultSharedSetup.sol";
import { Math } from "openzeppelin-contracts/contracts/utils/math/Math.sol";
import { RAY } from "./../../../../src/libraries/math/WadRayMath.sol";
import { WadRayMath, RAY } from "./../../../../src/libraries/math/WadRayMath.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";

using Math for uint256;
Expand Down
Loading