Skip to content

Commit

Permalink
Merge branch 'jun/PAG-C-01' into jun/PAG-M-04
Browse files Browse the repository at this point in the history
  • Loading branch information
junkim012 committed May 16, 2024
2 parents 8bdb209 + aade327 commit c21600c
Show file tree
Hide file tree
Showing 13 changed files with 386 additions and 195 deletions.
12 changes: 6 additions & 6 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 Down Expand Up @@ -512,7 +512,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 +570,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 +954,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
25 changes: 12 additions & 13 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,10 +448,10 @@ 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();
Expand All @@ -465,7 +463,7 @@ abstract contract RewardToken is
* @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 +492,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 +508,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 @@ -523,17 +524,15 @@ abstract contract RewardToken is
return _normalizedTotalSupply.rayMulDown($.supplyFactor + totalSupplyFactorIncrease);
}

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
24 changes: 11 additions & 13 deletions src/vault/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { Multicall } from "@openzeppelin/contracts/utils/Multicall.sol";
import { ReentrancyGuard } from "openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import { AccessControlDefaultAdminRules } from
"@openzeppelin/contracts/access/extensions/AccessControlDefaultAdminRules.sol";

/**
* @title Ion Lending Vault
* @author Molecular Labs
Expand All @@ -28,6 +27,7 @@ import { AccessControlDefaultAdminRules } from
*
* @custom:security-contact [email protected]
*/

contract Vault is ERC4626, Multicall, AccessControlDefaultAdminRules, ReentrancyGuard {
using EnumerableSet for EnumerableSet.AddressSet;
using Math for uint256;
Expand Down Expand Up @@ -197,10 +197,10 @@ contract Vault is ERC4626, Multicall, AccessControlDefaultAdminRules, Reentrancy
if (pool == IDLE) {
if (BASE_ASSET.balanceOf(address(this)) != 0) revert InvalidIdleMarketRemovalNonZeroBalance();
} else {
// Checks `balanceOf` as it may be possible that
// `getUnderlyingClaimOf` returns zero even though the
// Checks `normalizedBalanceOf` as it may be possible that
// `balanceOf` returns zero even though the
// `normalizedBalance` is zero.
if (pool.balanceOf(address(this)) != 0) revert InvalidMarketRemovalNonZeroSupply(pool);
if (pool.normalizedBalanceOf(address(this)) != 0) revert InvalidMarketRemovalNonZeroSupply(pool);
BASE_ASSET.approve(address(pool), 0);
}

Expand Down Expand Up @@ -323,7 +323,7 @@ contract Vault is ERC4626, Multicall, AccessControlDefaultAdminRules, Reentrancy
MarketAllocation calldata allocation = allocations[i];
IIonPool pool = allocation.pool;

uint256 currentSupplied = pool == IDLE ? currentIdleDeposits : pool.getUnderlyingClaimOf(address(this));
uint256 currentSupplied = pool == IDLE ? currentIdleDeposits : pool.balanceOf(address(this));
int256 assets = allocation.assets; // to deposit or withdraw

// if `assets` is `type(int256).min`, this means fully withdraw from the market.
Expand Down Expand Up @@ -645,7 +645,7 @@ contract Vault is ERC4626, Multicall, AccessControlDefaultAdminRules, Reentrancy

/**
* @notice Returns the total claim that the vault has across all supported IonPools.
* @dev `IonPool.getUnderlyingClaimOf` returns the rebasing balance of the
* @dev `IonPool.balanceOf` returns the rebasing balance of the
* lender receipt token that is pegged 1:1 to the underlying supplied asset.
* @return assets The total assets held on the contract and inside the underlying
* pools by this vault.
Expand All @@ -655,8 +655,7 @@ contract Vault is ERC4626, Multicall, AccessControlDefaultAdminRules, Reentrancy
for (uint256 i; i != _supportedMarketsLength;) {
IIonPool pool = IIonPool(supportedMarkets.at(i));

uint256 assetsInPool =
pool == IDLE ? BASE_ASSET.balanceOf(address(this)) : pool.getUnderlyingClaimOf(address(this));
uint256 assetsInPool = pool == IDLE ? BASE_ASSET.balanceOf(address(this)) : pool.balanceOf(address(this));

assets += assetsInPool;

Expand Down Expand Up @@ -763,7 +762,7 @@ contract Vault is ERC4626, Multicall, AccessControlDefaultAdminRules, Reentrancy
(feeShares, newTotalAssets) = _accruedFeeShares();
if (feeShares != 0) _mint(feeRecipient, feeShares);

lastTotalAssets = newTotalAssets; // This update happens outside of this function in Metamorpho.
lastTotalAssets = newTotalAssets;

emit FeeAccrued(feeShares, newTotalAssets);
}
Expand Down Expand Up @@ -897,7 +896,7 @@ contract Vault is ERC4626, Multicall, AccessControlDefaultAdminRules, Reentrancy
* @return The max amount of assets withdrawable from this IonPool.
*/
function _withdrawable(IIonPool pool) internal view returns (uint256) {
uint256 currentSupplied = pool.getUnderlyingClaimOf(address(this));
uint256 currentSupplied = pool.balanceOf(address(this));
uint256 availableLiquidity = uint256(pool.extsload(ION_POOL_LIQUIDITY_SLOT));

return Math.min(currentSupplied, availableLiquidity);
Expand All @@ -910,9 +909,8 @@ contract Vault is ERC4626, Multicall, AccessControlDefaultAdminRules, Reentrancy
* @return The max amount of assets depositable to this IonPool.
*/
function _depositable(IIonPool pool) internal view returns (uint256) {
uint256 allocationCapDiff = _zeroFloorSub(caps[pool], pool.getUnderlyingClaimOf(address(this)));
uint256 supplyCapDiff =
_zeroFloorSub(uint256(pool.extsload(ION_POOL_SUPPLY_CAP_SLOT)), pool.getTotalUnderlyingClaims());
uint256 allocationCapDiff = _zeroFloorSub(caps[pool], pool.balanceOf(address(this)));
uint256 supplyCapDiff = _zeroFloorSub(uint256(pool.extsload(ION_POOL_SUPPLY_CAP_SLOT)), pool.totalSupply());

return Math.min(allocationCapDiff, supplyCapDiff);
}
Expand Down
2 changes: 1 addition & 1 deletion test/fork/fuzz/lrt/EtherFiLibrary.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ contract EtherFiLibrary_FuzzTest is Test {

function testForkFuzz_GetLstAmountOutForEthAmountIn(uint256 ethAmount) external {
vm.assume(ethAmount != 0);
vm.assume(ethAmount < type(uint128).max);
vm.assume(ethAmount < type(uint96).max);

uint256 lrtAmountOut = EtherFiLibrary.getLstAmountOutForEthAmountIn(WEETH_ADDRESS, ethAmount);

Expand Down
11 changes: 4 additions & 7 deletions test/integration/concrete/WeEthIonPool.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ contract WeEthIonPool_IntegrationTest is WeEthIonPoolSharedSetup {
ionPool.supply(lenderA, lenderAFirstSupplyAmount, lenderProofs[0]);
vm.stopPrank();

assertEq(ionPool.getUnderlyingClaimOf(lenderA), lenderAFirstSupplyAmount, "lender balance after 1st supply");
assertEq(ionPool.balanceOf(lenderA), lenderAFirstSupplyAmount, "lender balance after 1st supply");
assertEq(lens.liquidity(iIonPool), lenderAFirstSupplyAmount, "liquidity after 1st supply");

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
Expand Down Expand Up @@ -172,10 +172,7 @@ contract WeEthIonPool_IntegrationTest is WeEthIonPoolSharedSetup {
uint256 roundingError = ionPool.supplyFactor() / 1e27;

assertApproxEqAbs(
ionPool.getUnderlyingClaimOf(lenderB),
lenderBFirstSupplyAmount,
roundingError,
"lenderB balance after 1st supply"
ionPool.balanceOf(lenderB), lenderBFirstSupplyAmount, roundingError, "lenderB balance after 1st supply"
);

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
Expand Down Expand Up @@ -219,14 +216,14 @@ contract WeEthIonPool_IntegrationTest is WeEthIonPoolSharedSetup {
vm.startPrank(lenderA);
ionPool.withdraw(lenderA, lender1WithdrawAmountFail);

uint256 lenderABalanceBefore = ionPool.getUnderlyingClaimOf(lenderA);
uint256 lenderABalanceBefore = ionPool.balanceOf(lenderA);

uint256 lender1WithdrawAmount = 10e18;
ionPool.withdraw(lenderA, lender1WithdrawAmount);
vm.stopPrank();

assertEq(
ionPool.getUnderlyingClaimOf(lenderA),
ionPool.balanceOf(lenderA),
lenderABalanceBefore - lender1WithdrawAmount,
"lenderA balance after 1st withdrawal"
);
Expand Down
11 changes: 7 additions & 4 deletions test/invariant/IonPool/ActorManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ contract IonPool_InvariantTest is IonPoolSharedSetup {

function invariant_LenderDepositsAddToBalance() external returns (bool) {
for (uint256 i = 0; i < lenders.length; i++) {
assertEq(lenders[i].totalHoldingsNormalized(), ionPool.balanceOf(address(lenders[i])));
assertEq(lenders[i].totalHoldingsNormalized(), ionPool.normalizedBalanceOf(address(lenders[i])));
}

return !failed();
Expand All @@ -236,9 +236,12 @@ contract IonPool_InvariantTest is IonPoolSharedSetup {
function invariant_LenderBalancesPlusTreasuryAddToTotalSupply() external returns (bool) {
uint256 totalLenderNormalizedBalances;
for (uint256 i = 0; i < lenders.length; i++) {
totalLenderNormalizedBalances += ionPool.balanceOf(address(lenders[i]));
totalLenderNormalizedBalances += ionPool.normalizedBalanceOf(address(lenders[i]));
}
assertEq(totalLenderNormalizedBalances + ionPool.balanceOf(TREASURY), ionPool.totalSupplyUnaccrued());
assertEq(
totalLenderNormalizedBalances + ionPool.normalizedBalanceOf(TREASURY),
ionPool.normalizedTotalSupplyUnaccrued()
);

return !failed();
}
Expand All @@ -256,7 +259,7 @@ contract IonPool_InvariantTest is IonPoolSharedSetup {
assertGe(lens.liquidity(iIonPool) + totalDebt, ionPool.totalSupplyUnaccrued());
assertGe(
lens.liquidity(iIonPool).scaleUpToRad(18) + lens.debtUnaccrued(iIonPool),
ionPool.totalSupplyUnaccrued() * ionPool.supplyFactorUnaccrued()
ionPool.normalizedTotalSupplyUnaccrued() * ionPool.supplyFactorUnaccrued()
);

return !failed();
Expand Down
8 changes: 4 additions & 4 deletions test/invariant/RewardToken/ActorManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -105,20 +105,20 @@ contract RewardToken_InvariantTest is RewardTokenSharedSetup {
uint256 totalSupplyByBalances;
for (uint256 i = 0; i < userHandlers.length; i++) {
UserHandler user = userHandlers[i];
totalSupplyByBalances += rewardModule.balanceOf(address(user));
totalSupplyByBalances += rewardModule.normalizedBalanceOf(address(user));
}

underlying.balanceOf(address(rewardModule)); // update underlying balance
rewardModule.totalSupply();

assertEq(rewardModule.totalSupply(), totalSupplyByBalances);
assertEq(rewardModule.normalizedTotalSupply(), totalSupplyByBalances);
}

function invariant_lenderClaimAlwaysBacked() external {
uint256 lenderClaim = rewardModule.getTotalUnderlyingClaims();
uint256 totalSupply = rewardModule.totalSupply();

uint256 underlyingBalance = underlying.balanceOf(address(rewardModule));

assertGe(underlyingBalance, lenderClaim);
assertGe(underlyingBalance, totalSupply);
}
}
8 changes: 4 additions & 4 deletions test/invariant/RewardToken/Handlers.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ contract UserHandler is Handler {
}

function burn(address account, uint256 amount) external {
amount = bound(amount, 0, REWARD_MODULE.getUnderlyingClaimOf(account));
amount = bound(amount, 0, REWARD_MODULE.balanceOf(account));
uint256 currentSupplyFactor = REWARD_MODULE.supplyFactor();

uint256 amountNormalized = amount.rayDivUp(currentSupplyFactor);
if (amountNormalized == 0 || amountNormalized > REWARD_MODULE.balanceOf(account)) return;
if (amountNormalized == 0 || amountNormalized > REWARD_MODULE.normalizedBalanceOf(account)) return;
REWARD_MODULE.burn(account, account, amount);
}

Expand All @@ -66,11 +66,11 @@ contract SupplyFactorIncreaseHandler is Handler {
uint256 oldSupplyFactor = REWARD_MODULE.supplyFactor();
amount = bound(amount, 1.1e27, 1.25e27); // between 1E-16 and 15%

uint256 oldTotalSupply = REWARD_MODULE.getTotalUnderlyingClaims();
uint256 oldTotalSupply = REWARD_MODULE.totalSupply();
uint256 newSupplyFactor = oldSupplyFactor.rayMulDown(amount);
REWARD_MODULE.setSupplyFactor(newSupplyFactor);

uint256 interestCreated = REWARD_MODULE.getTotalUnderlyingClaims() - oldTotalSupply;
uint256 interestCreated = REWARD_MODULE.totalSupply() - oldTotalSupply;
UNDERLYING.mint(address(REWARD_MODULE), interestCreated + 1);
}
}
Loading

0 comments on commit c21600c

Please sign in to comment.