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

C-01 Fix [PAG] #95

Merged
merged 33 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f32bb9c
fix: revert to rebasing RewardToken
junkim012 May 6, 2024
c7bf309
fix: querying unaccrued interest when paused, caching IDLE balance in…
junkim012 May 7, 2024
bc3ad91
fix: add max number of supported markets allowed
junkim012 May 11, 2024
971e8f6
fix: if paused, the depositable and withdrawable amount must be zero
junkim012 May 11, 2024
d9b87b2
fix: divide by zero in interest rate module when totalEthSupply is to…
junkim012 May 12, 2024
aade327
fix: revert the non-rebasing model of RewardToken to rebasing; change…
junkim012 May 12, 2024
c39ad6c
fix: when calculating total assets, query unaccrued balanceOf if the …
junkim012 May 12, 2024
1c6eefd
fix: update currentIdleDeposits counter when reallocating to and from…
junkim012 May 12, 2024
51102cc
fix: accrue fee before changing the feePercentage
junkim012 May 12, 2024
24f904c
fix: the total supply query now accounts for the treasury mint amount
junkim012 May 12, 2024
9a8acc2
fix: the _maxWithdraw includes fee shares
junkim012 May 12, 2024
3fc0bed
fix: if the supply or withdraw reverts, skip the market and move onto…
junkim012 May 13, 2024
0a29e38
test: show that depositing the allocation cap diff or supply cap diff…
junkim012 May 12, 2024
8bdb209
fix: instead of early exit, set utilization rate to zero if totalEthS…
junkim012 May 13, 2024
31eaad7
fix: if borrow rate is zero, only update the ilk last updated
junkim012 May 11, 2024
597dbf9
fix: handle interest accrual while paused in calculateRewardAndDebtDi…
junkim012 May 15, 2024
e463777
feat: to further defend against inflation attacks on top of virtual a…
junkim012 May 13, 2024
72a1354
feat: vault factory locks 1e3 shares minted by the deployer
junkim012 May 14, 2024
2074642
chore: fix natspec
junkim012 May 14, 2024
0c3fbb4
Merge pull request #97 from Ion-Protocol/jun/PAG-H-01
junkim012 May 16, 2024
6ab7ec6
Merge pull request #98 from Ion-Protocol/jun/PAG-M-02
junkim012 May 16, 2024
9742852
Merge pull request #99 from Ion-Protocol/jun/PAG-L-04
junkim012 May 16, 2024
ac80d55
Merge pull request #100 from Ion-Protocol/jun/PAG-L-03
junkim012 May 16, 2024
0bff3b2
Merge pull request #101 from Ion-Protocol/jun/PAG-L-10
junkim012 May 16, 2024
7802ed9
Merge pull request #94 from Ion-Protocol/jun/PAG-M-05
junkim012 May 16, 2024
c21600c
Merge branch 'jun/PAG-C-01' into jun/PAG-M-04
junkim012 May 16, 2024
27e8d3b
Merge branch 'jun/PAG-C-01' into jun/PAG-M-04
junkim012 May 16, 2024
226ebd8
Merge pull request #93 from Ion-Protocol/jun/PAG-M-04
junkim012 May 16, 2024
5f1fe86
Merge pull request #92 from Ion-Protocol/jun/PAG-L-09
junkim012 May 16, 2024
9c94f1a
Merge pull request #91 from Ion-Protocol/jun/PAG-L-07
junkim012 May 16, 2024
9c9a020
Merge branch 'jun/PAG-C-01' into jun/PAG-M-08
junkim012 May 16, 2024
c85a053
Merge pull request #90 from Ion-Protocol/jun/PAG-M-08
junkim012 May 16, 2024
1c826f4
chore: solhint disable next line for empty code blocks and import for…
junkim012 May 16, 2024
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
27 changes: 15 additions & 12 deletions src/IonPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ contract IonPool is PausableUpgradeable, RewardToken {
function _accrueInterest() internal returns (uint256 newTotalDebt) {
IonPoolStorage storage $ = _getIonPoolStorage();

uint256 totalEthSupply = getTotalUnderlyingClaimsUnaccrued();
uint256 totalEthSupply = totalSupplyUnaccrued();

uint256 totalSupplyFactorIncrease;
uint256 totalTreasuryMintAmount;
Expand Down Expand Up @@ -419,7 +419,7 @@ contract IonPool is PausableUpgradeable, RewardToken {
rateIncreases = new uint104[](ilksLength);
timestampIncreases = new uint48[](ilksLength);

uint256 totalEthSupply = getTotalUnderlyingClaimsUnaccrued();
uint256 totalEthSupply = totalSupplyUnaccrued();

for (uint8 i = 0; i < ilksLength;) {
(
Expand Down Expand Up @@ -457,7 +457,7 @@ contract IonPool is PausableUpgradeable, RewardToken {
returns (uint104 newRateIncrease, uint48 timestampIncrease)
{
(,, newRateIncrease,, timestampIncrease) =
_calculateRewardAndDebtDistributionForIlk(ilkIndex, getTotalUnderlyingClaimsUnaccrued());
_calculateRewardAndDebtDistributionForIlk(ilkIndex, totalSupplyUnaccrued());
}

function _calculateRewardAndDebtDistributionForIlk(
Expand All @@ -478,7 +478,10 @@ contract IonPool is PausableUpgradeable, RewardToken {
Ilk storage ilk = $.ilks[ilkIndex];

uint256 _totalNormalizedDebt = ilk.totalNormalizedDebt;
if (_totalNormalizedDebt == 0 || block.timestamp == ilk.lastRateUpdate) {
// Because all interest that would have accrued during a pause is
// cancelled upon `unpause`, we return zero interest while markets are
// paused.
if (_totalNormalizedDebt == 0 || block.timestamp == ilk.lastRateUpdate || paused()) {
// Unsafe cast OK
// block.timestamp - ilk.lastRateUpdate will almost always be 0
// here. The exception is on first borrow.
Expand All @@ -490,14 +493,14 @@ contract IonPool is PausableUpgradeable, RewardToken {
(uint256 borrowRate, uint256 reserveFactor) =
$.interestRateModule.calculateInterestRate(ilkIndex, totalDebt, totalEthSupply);

if (borrowRate == 0) return (0, 0, 0, 0, 0);

// Calculates borrowRate ^ (time) and returns the result with RAY precision
uint256 borrowRateExpT = _rpow(borrowRate + RAY, block.timestamp - ilk.lastRateUpdate, RAY);

// Unsafe cast OK
timestampIncrease = uint48(block.timestamp) - ilk.lastRateUpdate;

if (borrowRate == 0) return (0, 0, 0, 0, timestampIncrease);

// Calculates borrowRate ^ (time) and returns the result with RAY precision
uint256 borrowRateExpT = _rpow(borrowRate + RAY, timestampIncrease, RAY);

// Debt distribution
// This form of rate accrual is much safer than distributing the new
// debt increase to the total debt since low debt amounts won't cause
Expand All @@ -512,7 +515,7 @@ contract IonPool is PausableUpgradeable, RewardToken {
newDebtIncrease = _totalNormalizedDebt * newRateIncrease; // [RAD]

// Income distribution
uint256 _normalizedTotalSupply = totalSupplyUnaccrued(); // [WAD]
uint256 _normalizedTotalSupply = normalizedTotalSupplyUnaccrued(); // [WAD]

// If there is no supply, then nothing is being lent out.
supplyFactorIncrease = _normalizedTotalSupply == 0
Expand Down Expand Up @@ -570,7 +573,7 @@ contract IonPool is PausableUpgradeable, RewardToken {

uint256 _supplyCap = $.supplyCap;

if (getTotalUnderlyingClaims() > _supplyCap) revert DepositSurpassesSupplyCap(amount, _supplyCap);
if (totalSupply() > _supplyCap) revert DepositSurpassesSupplyCap(amount, _supplyCap);

emit Supply(user, _msgSender(), amount, _supplyFactor, newTotalDebt);
}
Expand Down Expand Up @@ -954,7 +957,7 @@ contract IonPool is PausableUpgradeable, RewardToken {
function getCurrentBorrowRate(uint8 ilkIndex) external view returns (uint256 borrowRate, uint256 reserveFactor) {
IonPoolStorage storage $ = _getIonPoolStorage();

uint256 totalEthSupply = getTotalUnderlyingClaimsUnaccrued();
uint256 totalEthSupply = totalSupplyUnaccrued();

uint256 _totalNormalizedDebt = $.ilks[ilkIndex].totalNormalizedDebt;
uint256 _rate = $.ilks[ilkIndex].rate;
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/IIonPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,5 @@ interface IIonPool {
function getTotalUnderlyingClaims() external view returns (uint256);
function getUnderlyingClaimOf(address user) external view returns (uint256);
function extsload(bytes32 slot) external view returns (bytes32);
function balanceOfUnaccrued(address user) external view returns (uint256);
}
37 changes: 22 additions & 15 deletions src/token/RewardToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,6 @@ abstract contract RewardToken is
$._normalizedBalances[from] = oldSenderBalance - amountNormalized;
}
$._normalizedBalances[to] += amountNormalized;

emit Transfer(from, to, amountNormalized);
}

/**
Expand Down Expand Up @@ -450,22 +448,30 @@ abstract contract RewardToken is
}

/**
* @dev Current token balance
* @dev Current claim of the underlying token inclusive of interest to be accrued.
* @param user to get balance of
*/
function getUnderlyingClaimOf(address user) public view returns (uint256) {
function balanceOf(address user) public view returns (uint256) {
RewardTokenStorage storage $ = _getRewardTokenStorage();

(uint256 totalSupplyFactorIncrease,,,,) = calculateRewardAndDebtDistribution();

return $._normalizedBalances[user].rayMulDown($.supplyFactor + totalSupplyFactorIncrease);
}

/**
* @dev Current claim of the underlying token without accounting for interest to be accrued.
*/
function balanceOfUnaccrued(address user) public view returns (uint256) {
RewardTokenStorage storage $ = _getRewardTokenStorage();
return $._normalizedBalances[user].rayMulDown($.supplyFactor);
}

/**
* @dev Accounting is done in normalized balances
* @param user to get normalized balance of
*/
function balanceOf(address user) external view returns (uint256) {
function normalizedBalanceOf(address user) external view returns (uint256) {
RewardTokenStorage storage $ = _getRewardTokenStorage();
return $._normalizedBalances[user];
}
Expand Down Expand Up @@ -494,7 +500,10 @@ abstract contract RewardToken is
return $.treasury;
}

function getTotalUnderlyingClaimsUnaccrued() public view returns (uint256) {
/**
* @dev Total claim of the underlying asset belonging to lenders not inclusive of the new interest to be accrued.
*/
function totalSupplyUnaccrued() public view returns (uint256) {
RewardTokenStorage storage $ = _getRewardTokenStorage();

uint256 _normalizedTotalSupply = $.normalizedTotalSupply;
Expand All @@ -507,9 +516,9 @@ abstract contract RewardToken is
}

/**
* @dev Total claim of the underlying asset belonging to lenders.
* @dev Total claim of the underlying asset belonging to lender inclusive of the new interest to be accrued.
*/
function getTotalUnderlyingClaims() public view returns (uint256) {
function totalSupply() public view returns (uint256) {
RewardTokenStorage storage $ = _getRewardTokenStorage();

uint256 _normalizedTotalSupply = $.normalizedTotalSupply;
Expand All @@ -518,22 +527,20 @@ abstract contract RewardToken is
return 0;
}

(uint256 totalSupplyFactorIncrease,,,,) = calculateRewardAndDebtDistribution();
(uint256 totalSupplyFactorIncrease, uint256 totalTreasuryMintAmount,,,) = calculateRewardAndDebtDistribution();

return _normalizedTotalSupply.rayMulDown($.supplyFactor + totalSupplyFactorIncrease);
return _normalizedTotalSupply.rayMulDown($.supplyFactor + totalSupplyFactorIncrease) + totalTreasuryMintAmount;
}

function totalSupplyUnaccrued() public view returns (uint256) {
function normalizedTotalSupplyUnaccrued() public view returns (uint256) {
RewardTokenStorage storage $ = _getRewardTokenStorage();
return $.normalizedTotalSupply;
}

/**
* @dev Current total supply
*
* Normalized total supply and total supply are same in non-rebasing token.
* @dev Normalized total supply.
*/
function totalSupply() public view returns (uint256) {
function normalizedTotalSupply() public view returns (uint256) {
RewardTokenStorage storage $ = _getRewardTokenStorage();

(uint256 totalSupplyFactorIncrease, uint256 totalTreasuryMintAmount,,,) = calculateRewardAndDebtDistribution();
Expand Down
Loading
Loading