diff --git a/snapshots/Hub.Operations.json b/snapshots/Hub.Operations.json index 10ee3a853..ed9a7c1f7 100644 --- a/snapshots/Hub.Operations.json +++ b/snapshots/Hub.Operations.json @@ -1,18 +1,18 @@ { - "add": "86709", - "add: with transfer": "108006", - "draw": "104177", - "eliminateDeficit: full": "72584", - "eliminateDeficit: partial": "82189", - "mintFeeShares": "82770", - "payFee": "70834", - "refreshPremium": "70391", - "remove: full": "75613", - "remove: partial": "80751", - "reportDeficit": "111899", - "restore: full": "76569", - "restore: full - with transfer": "169178", - "restore: partial": "85291", - "restore: partial - with transfer": "143271", - "transferShares": "69648" + "add": "69634", + "add: with transfer": "108031", + "draw": "111774", + "eliminateDeficit: full": "75503", + "eliminateDeficit: partial": "83138", + "mintFeeShares": "105283", + "payFee": "108553", + "refreshPremium": "72799", + "remove: full": "83259", + "remove: partial": "80768", + "reportDeficit": "153945", + "restore: full": "101515", + "restore: full - with transfer": "194074", + "restore: partial": "127337", + "restore: partial - with transfer": "185317", + "transferShares": "97067" } \ No newline at end of file diff --git a/snapshots/NativeTokenGateway.Operations.json b/snapshots/NativeTokenGateway.Operations.json index 85ac653d3..5c32276e5 100644 --- a/snapshots/NativeTokenGateway.Operations.json +++ b/snapshots/NativeTokenGateway.Operations.json @@ -1,8 +1,8 @@ { - "borrowNative": "227997", - "repayNative": "166265", - "supplyAsCollateralNative": "160205", - "supplyNative": "135802", - "withdrawNative: full": "125580", - "withdrawNative: partial": "136774" + "borrowNative": "233782", + "repayNative": "169207", + "supplyAsCollateralNative": "160230", + "supplyNative": "135822", + "withdrawNative: full": "127926", + "withdrawNative: partial": "137226" } \ No newline at end of file diff --git a/snapshots/SignatureGateway.Operations.json b/snapshots/SignatureGateway.Operations.json index 8ed7e3c5e..4e4560505 100644 --- a/snapshots/SignatureGateway.Operations.json +++ b/snapshots/SignatureGateway.Operations.json @@ -1,10 +1,10 @@ { - "borrowWithSig": "213175", - "repayWithSig": "186537", + "borrowWithSig": "216960", + "repayWithSig": "189479", "setSelfAsUserPositionManagerWithSig": "75385", "setUsingAsCollateralWithSig": "85409", - "supplyWithSig": "152034", + "supplyWithSig": "152054", "updateUserDynamicConfigWithSig": "63129", "updateUserRiskPremiumWithSig": "62099", - "withdrawWithSig": "130834" + "withdrawWithSig": "134494" } \ No newline at end of file diff --git a/snapshots/Spoke.Getters.json b/snapshots/Spoke.Getters.json index 0dfa4cbb0..b45f034b0 100644 --- a/snapshots/Spoke.Getters.json +++ b/snapshots/Spoke.Getters.json @@ -1,7 +1,7 @@ { "getUserAccountData: supplies: 0, borrows: 0": "13005", - "getUserAccountData: supplies: 1, borrows: 0": "49355", - "getUserAccountData: supplies: 2, borrows: 0": "80991", - "getUserAccountData: supplies: 2, borrows: 1": "100457", - "getUserAccountData: supplies: 2, borrows: 2": "119226" + "getUserAccountData: supplies: 1, borrows: 0": "51790", + "getUserAccountData: supplies: 2, borrows: 0": "85861", + "getUserAccountData: supplies: 2, borrows: 1": "107414", + "getUserAccountData: supplies: 2, borrows: 2": "128270" } \ No newline at end of file diff --git a/snapshots/Spoke.Operations.ZeroRiskPremium.json b/snapshots/Spoke.Operations.ZeroRiskPremium.json index b5c3abf57..d373809a5 100644 --- a/snapshots/Spoke.Operations.ZeroRiskPremium.json +++ b/snapshots/Spoke.Operations.ZeroRiskPremium.json @@ -1,33 +1,33 @@ { - "borrow: first": "189605", - "borrow: second action, same reserve": "169471", - "liquidationCall (receiveShares): full": "295608", - "liquidationCall (receiveShares): partial": "295326", - "liquidationCall: full": "305100", - "liquidationCall: partial": "304818", - "permitReserve + repay (multicall)": "164506", - "permitReserve + supply (multicall)": "146828", - "permitReserve + supply + enable collateral (multicall)": "161301", - "repay: full": "123800", - "repay: partial": "128770", + "borrow: first": "217073", + "borrow: second action, same reserve": "196826", + "liquidationCall (receiveShares): full": "344698", + "liquidationCall (receiveShares): partial": "344416", + "liquidationCall: full": "351885", + "liquidationCall: partial": "351603", + "permitReserve + repay (multicall)": "167361", + "permitReserve + supply (multicall)": "146853", + "permitReserve + supply + enable collateral (multicall)": "161326", + "repay: full": "126655", + "repay: partial": "131625", "setUserPositionManagersWithSig: disable": "47039", "setUserPositionManagersWithSig: enable": "68951", - "supply + enable collateral (multicall)": "141481", - "supply: 0 borrows, collateral disabled": "122874", - "supply: 0 borrows, collateral enabled": "105845", - "supply: second action, same reserve": "105774", + "supply + enable collateral (multicall)": "141506", + "supply: 0 borrows, collateral disabled": "122899", + "supply: 0 borrows, collateral enabled": "105870", + "supply: second action, same reserve": "105799", "updateUserDynamicConfig: 1 collateral": "74603", "updateUserDynamicConfig: 2 collaterals": "89520", - "updateUserRiskPremium: 1 borrow": "94940", - "updateUserRiskPremium: 2 borrows": "104075", + "updateUserRiskPremium: 1 borrow": "97244", + "updateUserRiskPremium: 2 borrows": "106361", "usingAsCollateral: 0 borrows, enable": "59638", - "usingAsCollateral: 1 borrow, disable": "104981", + "usingAsCollateral: 1 borrow, disable": "107285", "usingAsCollateral: 1 borrow, enable": "42526", - "usingAsCollateral: 2 borrows, disable": "126089", + "usingAsCollateral: 2 borrows, disable": "128375", "usingAsCollateral: 2 borrows, enable": "42538", - "withdraw: 0 borrows, full": "127997", - "withdraw: 0 borrows, partial": "132732", - "withdraw: 1 borrow, partial": "159169", - "withdraw: 2 borrows, partial": "173287", - "withdraw: non collateral": "105920" + "withdraw: 0 borrows, full": "131165", + "withdraw: 0 borrows, partial": "133619", + "withdraw: 1 borrow, partial": "162754", + "withdraw: 2 borrows, partial": "176243", + "withdraw: non collateral": "106372" } \ No newline at end of file diff --git a/snapshots/Spoke.Operations.json b/snapshots/Spoke.Operations.json index 42d769150..77643397f 100644 --- a/snapshots/Spoke.Operations.json +++ b/snapshots/Spoke.Operations.json @@ -1,33 +1,33 @@ { - "borrow: first": "258588", - "borrow: second action, same reserve": "201454", - "liquidationCall (receiveShares): full": "327696", - "liquidationCall (receiveShares): partial": "327414", - "liquidationCall: full": "337188", - "liquidationCall: partial": "336906", - "permitReserve + repay (multicall)": "161988", - "permitReserve + supply (multicall)": "146828", - "permitReserve + supply + enable collateral (multicall)": "161301", - "repay: full": "117879", - "repay: partial": "137249", + "borrow: first": "283751", + "borrow: second action, same reserve": "226504", + "liquidationCall (receiveShares): full": "357381", + "liquidationCall (receiveShares): partial": "357099", + "liquidationCall: full": "364568", + "liquidationCall: partial": "364286", + "permitReserve + repay (multicall)": "164272", + "permitReserve + supply (multicall)": "146853", + "permitReserve + supply + enable collateral (multicall)": "161326", + "repay: full": "120734", + "repay: partial": "140104", "setUserPositionManagersWithSig: disable": "47039", "setUserPositionManagersWithSig: enable": "68951", - "supply + enable collateral (multicall)": "141481", - "supply: 0 borrows, collateral disabled": "122874", - "supply: 0 borrows, collateral enabled": "105845", - "supply: second action, same reserve": "105774", + "supply + enable collateral (multicall)": "141506", + "supply: 0 borrows, collateral disabled": "122899", + "supply: 0 borrows, collateral enabled": "105870", + "supply: second action, same reserve": "105799", "updateUserDynamicConfig: 1 collateral": "74603", "updateUserDynamicConfig: 2 collaterals": "89520", - "updateUserRiskPremium: 1 borrow": "148344", - "updateUserRiskPremium: 2 borrows": "198096", + "updateUserRiskPremium: 1 borrow": "195116", + "updateUserRiskPremium: 2 borrows": "287318", "usingAsCollateral: 0 borrows, enable": "59638", - "usingAsCollateral: 1 borrow, disable": "158385", + "usingAsCollateral: 1 borrow, disable": "205157", "usingAsCollateral: 1 borrow, enable": "42526", - "usingAsCollateral: 2 borrows, disable": "228110", + "usingAsCollateral: 2 borrows, disable": "319332", "usingAsCollateral: 2 borrows, enable": "42538", - "withdraw: 0 borrows, full": "127997", - "withdraw: 0 borrows, partial": "132732", - "withdraw: 1 borrow, partial": "210071", - "withdraw: 2 borrows, partial": "255841", - "withdraw: non collateral": "105920" + "withdraw: 0 borrows, full": "131165", + "withdraw: 0 borrows, partial": "133619", + "withdraw: 1 borrow, partial": "258124", + "withdraw: 2 borrows, partial": "261892", + "withdraw: non collateral": "106372" } \ No newline at end of file diff --git a/src/hub/Hub.sol b/src/hub/Hub.sol index c77d1a76c..2a64d0370 100644 --- a/src/hub/Hub.sol +++ b/src/hub/Hub.sol @@ -96,6 +96,7 @@ contract Hub is IHub, AccessManaged { uint256 lastUpdateTimestamp = block.timestamp; _assets[assetId] = Asset({ liquidity: 0, + realizedFeesRay: 0, deficitRay: 0, swept: 0, addedShares: 0, @@ -108,7 +109,6 @@ contract Hub is IHub, AccessManaged { decimals: decimals, drawnRate: drawnRate.toUint96(), irStrategy: irStrategy, - realizedFees: 0, reinvestmentController: address(0), feeReceiver: feeReceiver, liquidityFee: 0 @@ -125,7 +125,7 @@ contract Hub is IHub, AccessManaged { reinvestmentController: address(0) }) ); - emit UpdateAsset(assetId, drawnIndex, drawnRate, 0); + emit UpdateAsset(assetId, drawnIndex, drawnRate); return assetId; } @@ -152,7 +152,6 @@ contract Hub is IHub, AccessManaged { address oldFeeReceiver = asset.feeReceiver; if (oldFeeReceiver != config.feeReceiver) { - _mintFeeShares(asset, assetId); IHub.SpokeConfig memory spokeConfig; spokeConfig.active = _spokes[assetId][oldFeeReceiver].active; spokeConfig.halted = _spokes[assetId][oldFeeReceiver].halted; @@ -168,7 +167,7 @@ contract Hub is IHub, AccessManaged { require(irData.length == 0, InvalidInterestRateStrategy()); } - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); emit UpdateAssetConfig(assetId, config); } @@ -202,17 +201,7 @@ contract Hub is IHub, AccessManaged { Asset storage asset = _assets[assetId]; asset.accrue(); IBasicInterestRateStrategy(asset.irStrategy).setInterestRateData(assetId, irData); - asset.updateDrawnRate(assetId); - } - - /// @inheritdoc IHub - function mintFeeShares(uint256 assetId) external restricted returns (uint256) { - require(assetId < _assetCount, AssetNotListed()); - Asset storage asset = _assets[assetId]; - asset.accrue(); - uint256 feeShares = _mintFeeShares(asset, assetId); - asset.updateDrawnRate(assetId); - return feeShares; + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); } /// @inheritdoc IHubBase @@ -232,7 +221,7 @@ contract Hub is IHub, AccessManaged { spoke.addedShares += shares; asset.liquidity = liquidity.toUint120(); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); emit Add(assetId, msg.sender, shares, amount); @@ -255,7 +244,7 @@ contract Hub is IHub, AccessManaged { spoke.addedShares -= shares; asset.liquidity = liquidity.uncheckedSub(amount).toUint120(); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); IERC20(asset.underlying).safeTransfer(to, amount); @@ -280,7 +269,7 @@ contract Hub is IHub, AccessManaged { spoke.drawnShares += drawnShares; asset.liquidity = liquidity.uncheckedSub(amount).toUint120(); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); IERC20(asset.underlying).safeTransfer(to, amount); @@ -312,7 +301,7 @@ contract Hub is IHub, AccessManaged { require(balance >= liquidity, InsufficientTransferred(liquidity.uncheckedSub(balance))); asset.liquidity = liquidity.toUint120(); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); emit Restore(assetId, msg.sender, drawnShares, premiumDelta, drawnAmount, premiumAmount); @@ -341,7 +330,7 @@ contract Hub is IHub, AccessManaged { asset.deficitRay += deficitAmountRay.toUint200(); spoke.deficitRay += deficitAmountRay.toUint200(); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); emit ReportDeficit(assetId, msg.sender, drawnShares, premiumDelta, deficitAmountRay); @@ -369,7 +358,7 @@ contract Hub is IHub, AccessManaged { asset.deficitRay -= deficitAmountRay.toUint200(); coveredSpoke.deficitRay -= deficitAmountRay.toUint200(); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); emit EliminateDeficit(assetId, msg.sender, spoke, shares, deficitAmountRay); @@ -386,7 +375,7 @@ contract Hub is IHub, AccessManaged { // no premium change allowed require(premiumDelta.restoredPremiumRay == 0, InvalidPremiumChange()); _applyPremiumDelta(asset, spoke, premiumDelta); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); emit RefreshPremium(assetId, msg.sender, premiumDelta); } @@ -401,7 +390,7 @@ contract Hub is IHub, AccessManaged { asset.accrue(); _validatePayFeeShares(sender, shares); _transferShares(sender, receiver, shares); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); emit TransferShares(assetId, msg.sender, feeReceiver, shares); } @@ -415,7 +404,7 @@ contract Hub is IHub, AccessManaged { asset.accrue(); _validateTransferShares(asset, sender, receiver, shares); _transferShares(sender, receiver, shares); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); emit TransferShares(assetId, msg.sender, toSpoke, shares); } @@ -434,7 +423,7 @@ contract Hub is IHub, AccessManaged { asset.liquidity = liquidity.uncheckedSub(amount).toUint120(); asset.swept += amount.toUint120(); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); IERC20(asset.underlying).safeTransfer(msg.sender, amount); @@ -455,7 +444,7 @@ contract Hub is IHub, AccessManaged { asset.liquidity = liquidity.toUint120(); asset.swept -= amount.toUint120(); - asset.updateDrawnRate(assetId); + asset.updateDrawnRateAndMintFeeShares(_spokes, assetId); emit Reclaim(assetId, msg.sender, amount); } @@ -602,7 +591,7 @@ contract Hub is IHub, AccessManaged { /// @inheritdoc IHub function getAssetAccruedFees(uint256 assetId) external view returns (uint256) { Asset storage asset = _assets[assetId]; - return asset.realizedFees + asset.getUnrealizedFees(asset.getDrawnIndex()); + return asset.getUnrealizedFees(asset.getDrawnIndex()); } /// @inheritdoc IHub @@ -779,25 +768,6 @@ contract Hub is IHub, AccessManaged { ); } - function _mintFeeShares(Asset storage asset, uint256 assetId) internal returns (uint256) { - uint256 fees = asset.realizedFees; - uint120 shares = asset.toAddedSharesDown(fees).toUint120(); - if (shares == 0) { - return 0; - } - - address feeReceiver = asset.feeReceiver; - SpokeData storage feeReceiverSpoke = _spokes[assetId][feeReceiver]; - require(feeReceiverSpoke.active, SpokeNotActive()); - - asset.addedShares += shares; - feeReceiverSpoke.addedShares += shares; - asset.realizedFees = 0; - emit MintFeeShares(assetId, feeReceiver, shares, fees); - - return shares; - } - /// @dev Returns the spoke's drawn amount for a specified asset. function _getSpokeDrawn( Asset storage asset, diff --git a/src/hub/interfaces/IHub.sol b/src/hub/interfaces/IHub.sol index 60ee2ca83..6d8dac71c 100644 --- a/src/hub/interfaces/IHub.sol +++ b/src/hub/interfaces/IHub.sol @@ -29,22 +29,19 @@ interface IHub is IHubBase, IAccessManaged { /// @dev deficitRay The amount of outstanding bad debt across all spokes, expressed in asset units and scaled by RAY. struct Asset { uint120 liquidity; - uint120 realizedFees; - uint8 decimals; - // uint120 addedShares; - uint120 swept; - // - int200 premiumOffsetRay; + uint8 decimals; // + uint120 drawnIndex; uint120 drawnShares; - uint120 premiumShares; uint16 liquidityFee; // - uint120 drawnIndex; + uint120 premiumShares; uint96 drawnRate; uint40 lastUpdateTimestamp; // + uint120 swept; + // address underlying; // address irStrategy; @@ -53,7 +50,10 @@ interface IHub is IHubBase, IAccessManaged { // address feeReceiver; // + int200 premiumOffsetRay; uint200 deficitRay; + // + uint200 realizedFeesRay; } /// @notice Asset configuration. Subset of the `Asset` struct. @@ -110,13 +110,7 @@ interface IHub is IHubBase, IAccessManaged { /// @param assetId The identifier of the asset. /// @param drawnIndex The new drawn index of the asset. /// @param drawnRate The new drawn rate of the asset. - /// @param accruedFees The accrued fees of the asset since the last mint. - event UpdateAsset( - uint256 indexed assetId, - uint256 drawnIndex, - uint256 drawnRate, - uint256 accruedFees - ); + event UpdateAsset(uint256 indexed assetId, uint256 drawnIndex, uint256 drawnRate); /// @notice Emitted when an asset configuration is updated. /// @param assetId The identifier of the asset. @@ -298,12 +292,6 @@ interface IHub is IHubBase, IAccessManaged { /// @param irData The interest rate data to apply to the given asset, encoded in bytes. function setInterestRateData(uint256 assetId, bytes calldata irData) external; - /// @notice Mints shares to the fee receiver from accrued fees. - /// @dev No op when fees are worth less than one share. - /// @param assetId The identifier of the asset. - /// @return The amount of shares minted. - function mintFeeShares(uint256 assetId) external returns (uint256); - /// @notice Eliminates deficit by removing supplied shares of caller spoke. /// @dev Only callable by active and authorized spokes. /// @param assetId The identifier of the asset. diff --git a/src/hub/libraries/AssetLogic.sol b/src/hub/libraries/AssetLogic.sol index 2b4f44cb4..128cbcd7a 100644 --- a/src/hub/libraries/AssetLogic.sol +++ b/src/hub/libraries/AssetLogic.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.20; import {SafeCast} from 'src/dependencies/openzeppelin/SafeCast.sol'; +import {TransientSlot} from 'src/dependencies/openzeppelin/TransientSlot.sol'; import {MathUtils} from 'src/libraries/math/MathUtils.sol'; import {PercentageMath} from 'src/libraries/math/PercentageMath.sol'; import {WadRayMath} from 'src/libraries/math/WadRayMath.sol'; @@ -21,6 +22,25 @@ library AssetLogic { using PercentageMath for uint256; using WadRayMath for *; using SharesMath for uint256; + using TransientSlot for *; + + /// bytes32(uint256(keccak256("PERFECT_FEE_AMOUNT_RAY")) - 1) + TransientSlot.Uint256Slot internal constant PERFECT_FEE_AMOUNT_RAY_SLOT = + TransientSlot.Uint256Slot.wrap( + 0x722bee6a2d618e3f3bdf2d4fb44e4c32c59f42793a03753a97199ff83fbea63d + ); + + /// bytes32(uint256(keccak256("TOTAL_FEE_AMOUNT_RAY")) - 1) + TransientSlot.Uint256Slot internal constant TOTAL_FEE_AMOUNT_RAY_SLOT = + TransientSlot.Uint256Slot.wrap( + 0x428ed7a6206e7d905830bdd689c57e1b0c8b67ff6fac36f5bba6a67cd7024b16 + ); + + /// bytes32(uint256(keccak256("FEE_SHARES")) - 1) + TransientSlot.Uint256Slot internal constant FEE_SHARES_SLOT = + TransientSlot.Uint256Slot.wrap( + 0x0f70ea74dd445701867e94c5b4520c3ee79405fb0cb270d985de5a2c5e26004a + ); /// @notice Converts an amount of shares to the equivalent amount of drawn assets, rounding up. function toDrawnAssetsUp( @@ -79,20 +99,23 @@ library AssetLogic { /// @notice Returns the total added assets for the specified asset. function totalAddedAssets(IHub.Asset storage asset) internal view returns (uint256) { uint256 drawnIndex = asset.getDrawnIndex(); + uint256 totalAddedSupplierAssets = asset.liquidity + + asset.swept + + _calculateAggregatedOwedRay({ + drawnShares: asset.drawnShares, + premiumShares: asset.premiumShares, + premiumOffsetRay: asset.premiumOffsetRay, + deficitRay: asset.deficitRay, + drawnIndex: drawnIndex + }).fromRayUp(); - uint256 aggregatedOwedRay = _calculateAggregatedOwedRay({ - drawnShares: asset.drawnShares, - premiumShares: asset.premiumShares, - premiumOffsetRay: asset.premiumOffsetRay, - deficitRay: asset.deficitRay, - drawnIndex: drawnIndex - }); - + uint256 feeAmount = TOTAL_FEE_AMOUNT_RAY_SLOT.tload().fromRayDown(); + if (feeAmount > 0) { + return totalAddedSupplierAssets - feeAmount; + } return - asset.liquidity + - asset.swept + - aggregatedOwedRay.fromRayUp() - - asset.realizedFees - + totalAddedSupplierAssets - + asset.realizedFeesRay.fromRayDown() - asset.getUnrealizedFees(drawnIndex); } @@ -128,11 +151,15 @@ library AssetLogic { return assets.toSharesDown(asset.totalAddedAssets(), asset.addedShares); } - /// @notice Updates the drawn rate of a specified asset. + /// @notice Updates the drawn rate of a specified asset and mints fee shares. /// @dev Premium debt is not used in the interest rate calculation. /// @dev Uses last stored index; asset accrual should have already occurred. /// @dev Imprecision from downscaling `deficitRay` does not accumulate. - function updateDrawnRate(IHub.Asset storage asset, uint256 assetId) internal { + function updateDrawnRateAndMintFeeShares( + IHub.Asset storage asset, + mapping(uint256 assetId => mapping(address spoke => IHub.SpokeData)) storage spokes, + uint256 assetId + ) internal { uint256 drawnIndex = asset.drawnIndex; uint256 newDrawnRate = IBasicInterestRateStrategy(asset.irStrategy).calculateInterestRate({ assetId: assetId, @@ -143,7 +170,21 @@ library AssetLogic { }); asset.drawnRate = newDrawnRate.toUint96(); - emit IHub.UpdateAsset(assetId, drawnIndex, newDrawnRate, asset.realizedFees); + uint256 feeAmountRay = TOTAL_FEE_AMOUNT_RAY_SLOT.tload(); + uint256 perfectFeeAmountRay = PERFECT_FEE_AMOUNT_RAY_SLOT.tload(); + uint120 feeShares = FEE_SHARES_SLOT.tload().toUint120(); + if (feeShares > 0) { + address feeReceiver = asset.feeReceiver; + asset.addedShares += feeShares; + spokes[assetId][feeReceiver].addedShares += feeShares; + FEE_SHARES_SLOT.tstore(0); + emit IHub.MintFeeShares(assetId, feeReceiver, feeShares, perfectFeeAmountRay.fromRayDown()); + } + asset.realizedFeesRay = (feeAmountRay - perfectFeeAmountRay).toUint200(); + TOTAL_FEE_AMOUNT_RAY_SLOT.tstore(0); + PERFECT_FEE_AMOUNT_RAY_SLOT.tstore(0); + + emit IHub.UpdateAsset(assetId, drawnIndex, newDrawnRate); } /// @notice Accrues interest and fees for the specified asset. @@ -153,7 +194,12 @@ library AssetLogic { } uint256 drawnIndex = asset.getDrawnIndex(); - asset.realizedFees += asset.getUnrealizedFees(drawnIndex).toUint120(); + uint256 feeAmountRay = asset.realizedFeesRay + asset.getUnrealizedFees(drawnIndex).toRay(); + uint256 feeShares = asset.toAddedSharesDown(feeAmountRay.fromRayDown()); + uint256 perfectFeeAmountRay = feeShares == 0 ? 0 : asset.toAddedAssetsUp(feeShares.toRay()); + TOTAL_FEE_AMOUNT_RAY_SLOT.tstore(feeAmountRay); + PERFECT_FEE_AMOUNT_RAY_SLOT.tstore(perfectFeeAmountRay); + FEE_SHARES_SLOT.tstore(feeShares); asset.drawnIndex = drawnIndex.toUint120(); asset.lastUpdateTimestamp = block.timestamp.toUint40(); } diff --git a/src/libraries/math/WadRayMath.sol b/src/libraries/math/WadRayMath.sol index 3ffaf8299..3a1af4cf7 100644 --- a/src/libraries/math/WadRayMath.sol +++ b/src/libraries/math/WadRayMath.sol @@ -162,6 +162,14 @@ library WadRayMath { } } + /// @notice Removes RAY precision from a given value, rounding down. + /// @return b = a / RAY. + function fromRayDown(uint256 a) internal pure returns (uint256 b) { + assembly ('memory-safe') { + b := div(a, RAY) + } + } + /// @notice Removes RAY precision from a given value, rounding up. /// @return b = ceil(a / RAY). function fromRayUp(uint256 a) internal pure returns (uint256 b) { diff --git a/tests/Base.t.sol b/tests/Base.t.sol index e6d714a84..37268bacb 100644 --- a/tests/Base.t.sol +++ b/tests/Base.t.sol @@ -351,7 +351,7 @@ abstract contract Base is Test { selectors[2] = IHub.addSpoke.selector; selectors[3] = IHub.updateSpokeConfig.selector; selectors[4] = IHub.setInterestRateData.selector; - selectors[5] = IHub.mintFeeShares.selector; + // selectors[5] = IHub.mintFeeShares.selector; manager.setTargetFunctionRole(address(targetHub), selectors, Roles.HUB_ADMIN_ROLE); } @@ -2252,12 +2252,12 @@ abstract contract Base is Test { /// @dev Helper function to withdraw fees from the treasury spoke function _withdrawLiquidityFees(IHub hub, uint256 assetId, uint256 amount) internal { - Utils.mintFeeShares(hub, assetId, ADMIN); + // Utils.mintFeeShares(hub, assetId, ADMIN); uint256 fees = hub.getSpokeAddedAssets(assetId, address(treasurySpoke)); - if (amount > fees) { - amount = fees; - } + // if (amount > fees) { + // amount = fees; + // } if (amount == 0) { return; // nothing to withdraw } @@ -2984,15 +2984,12 @@ abstract contract Base is Test { IHub hub, uint256 assetId ) internal view returns (uint256) { - uint256 expectedFees = hub.getAsset(assetId).realizedFees + _calcUnrealizedFees(hub, assetId); + uint256 expectedFees = _calcUnrealizedFees(hub, assetId); assertEq(expectedFees, hub.getAssetAccruedFees(assetId), 'asset accrued fees'); return hub.getSpokeAddedAssets(assetId, hub.getAsset(assetId).feeReceiver) + expectedFees; } function _getAddedAssetsWithFees(IHub hub, uint256 assetId) internal view returns (uint256) { - return - hub.getAddedAssets(assetId) + - hub.getAsset(assetId).realizedFees + - _calcUnrealizedFees(hub, assetId); + return hub.getAddedAssets(assetId) + _calcUnrealizedFees(hub, assetId); } } diff --git a/tests/Utils.sol b/tests/Utils.sol index d02fb097c..09645d4ae 100644 --- a/tests/Utils.sol +++ b/tests/Utils.sol @@ -174,10 +174,10 @@ library Utils { spoke.repay(reserveId, amount, onBehalfOf); } - function mintFeeShares(IHub hub, uint256 assetId, address caller) internal returns (uint256) { - vm.prank(caller); - return hub.mintFeeShares(assetId); - } + // function mintFeeShares(IHub hub, uint256 assetId, address caller) internal returns (uint256) { + // vm.prank(caller); + // return hub.mintFeeShares(assetId); + // } function approve(ISpoke spoke, uint256 reserveId, address owner, uint256 amount) internal { address underlying = spoke.getReserve(reserveId).underlying; diff --git a/tests/gas/Hub.Operations.gas.t.sol b/tests/gas/Hub.Operations.gas.t.sol index a54761a0b..1ccc60566 100644 --- a/tests/gas/Hub.Operations.gas.t.sol +++ b/tests/gas/Hub.Operations.gas.t.sol @@ -221,7 +221,7 @@ contract HubOperations_Gas_Tests is Base { skip(100); - Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // Utils.mintFeeShares(hub1, daiAssetId, ADMIN); vm.snapshotGasLastCall('Hub.Operations', 'mintFeeShares'); } diff --git a/tests/unit/Hub/Hub.Config.t.sol b/tests/unit/Hub/Hub.Config.t.sol index 42cfde53b..7122722f3 100644 --- a/tests/unit/Hub/Hub.Config.t.sol +++ b/tests/unit/Hub/Hub.Config.t.sol @@ -330,7 +330,7 @@ contract HubConfigTest is HubBase { vm.expectEmit(address(hub1)); emit IHub.UpdateAssetConfig(expectedAssetId, expectedConfig); vm.expectEmit(address(hub1)); - emit IHub.UpdateAsset(expectedAssetId, WadRayMath.RAY, baseVariableBorrowRate.bpsToRay(), 0); + emit IHub.UpdateAsset(expectedAssetId, WadRayMath.RAY, baseVariableBorrowRate.bpsToRay()); uint256 assetId = Utils.addAsset( hub1, @@ -534,8 +534,7 @@ contract HubConfigTest is HubBase { drawn: drawn, deficit: 0, swept: 0 - }), - isNewFeeReceiver ? 0 : hub1.getAssetAccruedFees(assetId) + }) ); vm.expectEmit(address(hub1)); emit IHub.UpdateAssetConfig(assetId, newConfig); @@ -679,7 +678,7 @@ contract HubConfigTest is HubBase { _drawLiquidity(assetId, amount, true); skip(365 days); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); _updateSpokeActive(hub1, assetId, _getFeeReceiver(hub1, assetId), false); IHub.AssetConfig memory config = hub1.getAssetConfig(assetId); @@ -699,7 +698,7 @@ contract HubConfigTest is HubBase { uint256 oldFees = hub1.getSpokeAddedShares(assetId, oldFeeReceiver); skip(365 days); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); IHub.AssetConfig memory config = hub1.getAssetConfig(assetId); address newFeeReceiver = config.feeReceiver; diff --git a/tests/unit/Hub/Hub.Draw.t.sol b/tests/unit/Hub/Hub.Draw.t.sol index 1f7cdf63e..b06cde3b2 100644 --- a/tests/unit/Hub/Hub.Draw.t.sol +++ b/tests/unit/Hub/Hub.Draw.t.sol @@ -45,8 +45,7 @@ contract HubDrawTest is HubBase { drawn: hub1.previewRestoreByShares(assetId, assetBefore.drawnShares + shares), deficit: assetBefore.deficitRay, swept: assetBefore.swept - }), - hub1.getAssetAccruedFees(assetId) + }) ); vm.expectEmit(address(hub1.getAsset(assetId).underlying)); emit IERC20.Transfer(address(hub1), alice, amount); @@ -131,8 +130,7 @@ contract HubDrawTest is HubBase { drawn: hub1.previewRestoreByShares(assetId, assetBefore.drawnShares + shares), deficit: assetBefore.deficitRay, swept: assetBefore.swept - }), - hub1.getAssetAccruedFees(assetId) + }) ); vm.expectEmit(address(hub1.getAsset(assetId).underlying)); emit IERC20.Transfer(address(hub1), alice, amount); diff --git a/tests/unit/Hub/Hub.MintFeeShares.t.sol b/tests/unit/Hub/Hub.MintFeeShares.t.sol index 443adb4a1..1437afb58 100644 --- a/tests/unit/Hub/Hub.MintFeeShares.t.sol +++ b/tests/unit/Hub/Hub.MintFeeShares.t.sol @@ -9,7 +9,7 @@ contract HubMintFeeSharesTest is HubBase { vm.expectRevert( abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, address(this)) ); - Utils.mintFeeShares(hub1, daiAssetId, address(this)); + // Utils.mintFeeShares(hub1, daiAssetId, address(this)); } function test_mintFeeShares_revertsWith_SpokeNotActive() public { @@ -28,13 +28,13 @@ contract HubMintFeeSharesTest is HubBase { _updateSpokeActive(hub1, daiAssetId, _getFeeReceiver(hub1, daiAssetId), false); vm.expectRevert(IHub.SpokeNotActive.selector, address(hub1)); - Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // Utils.mintFeeShares(hub1, daiAssetId, ADMIN); } function test_mintFeeShares_revertsWith_AssetNotListed() public { uint256 invalidAssetId = hub1.getAssetCount(); vm.expectRevert(IHub.AssetNotListed.selector); - Utils.mintFeeShares(hub1, invalidAssetId, ADMIN); + // Utils.mintFeeShares(hub1, invalidAssetId, ADMIN); } function test_mintFeeShares() public { @@ -54,7 +54,7 @@ contract HubMintFeeSharesTest is HubBase { address feeReceiver = _getFeeReceiver(hub1, daiAssetId); // before mintFeeShares, the fee shares should be 0 - uint256 realizedFees = hub1.getAsset(daiAssetId).realizedFees; + uint256 realizedFees = hub1.getAsset(daiAssetId).realizedFeesRay; assertEq(realizedFees, 0); uint256 feeShares = hub1.getSpokeAddedShares(daiAssetId, feeReceiver); assertEq(feeShares, 0); @@ -80,22 +80,22 @@ contract HubMintFeeSharesTest is HubBase { vm.expectEmit(address(hub1)); emit IHub.MintFeeShares(daiAssetId, feeReceiver, expectedMintedShares, expectedMintedAssets); vm.expectEmit(address(hub1)); - emit IHub.UpdateAsset(daiAssetId, hub1.getAssetDrawnIndex(daiAssetId), mockRate, 0); + emit IHub.UpdateAsset(daiAssetId, hub1.getAssetDrawnIndex(daiAssetId), mockRate); uint256 addedSharesBefore = hub1.getAddedShares(daiAssetId); uint256 sharePriceBefore = hub1.previewAddByShares(daiAssetId, 1e18); vm.expectCall(address(irStrategy), irCalldata); - uint256 mintedShares = Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // uint256 mintedShares = Utils.mintFeeShares(hub1, daiAssetId, ADMIN); - assertEq(mintedShares, expectedMintedShares, 'minted shares'); - assertEq(hub1.getAsset(daiAssetId).realizedFees, 0, 'realized fees after'); + // assertEq(mintedShares, expectedMintedShares, 'minted shares'); + assertEq(hub1.getAsset(daiAssetId).realizedFeesRay, 0, 'realized fees after'); assertEq( hub1.getSpokeAddedShares(daiAssetId, feeReceiver), expectedMintedShares, 'added shares' ); - assertEq(mintedShares, hub1.getAddedShares(daiAssetId) - addedSharesBefore, 'minted shares'); + // assertEq(mintedShares, hub1.getAddedShares(daiAssetId) - addedSharesBefore, 'minted shares'); assertGe(hub1.previewAddByShares(daiAssetId, 1e18), sharePriceBefore, 'share price'); } @@ -108,10 +108,10 @@ contract HubMintFeeSharesTest is HubBase { _updateSpokeActive(hub1, daiAssetId, _getFeeReceiver(hub1, daiAssetId), false); vm.expectEmit(address(hub1)); - emit IHub.UpdateAsset(daiAssetId, asset.drawnIndex, asset.drawnRate, 0); + emit IHub.UpdateAsset(daiAssetId, asset.drawnIndex, asset.drawnRate); vm.recordLogs(); - Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // Utils.mintFeeShares(hub1, daiAssetId, ADMIN); vm.getRecordedLogs(); _assertEventNotEmitted(IHub.MintFeeShares.selector); } @@ -140,17 +140,17 @@ contract HubMintFeeSharesTest is HubBase { updateLiquidityFee(hub1, daiAssetId, PercentageMath.PERCENTAGE_FACTOR); // mint fee shares just to accrue (liquidity fee is 0, so no fees are minted) - Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // Utils.mintFeeShares(hub1, daiAssetId, ADMIN); skip(365 days); // drawn index is 2.000...001 assertEq(hub1.getAssetDrawnIndex(daiAssetId), 2e27 + 1); vm.recordLogs(); - Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // Utils.mintFeeShares(hub1, daiAssetId, ADMIN); vm.getRecordedLogs(); _assertEventNotEmitted(IHub.MintFeeShares.selector); - assertEq(hub1.getAsset(daiAssetId).realizedFees, 1, 'realized fees after'); + assertEq(hub1.getAsset(daiAssetId).realizedFeesRay, 1, 'realized fees after'); } } diff --git a/tests/unit/Hub/Hub.Remove.t.sol b/tests/unit/Hub/Hub.Remove.t.sol index 0eac78169..71ce84d2d 100644 --- a/tests/unit/Hub/Hub.Remove.t.sol +++ b/tests/unit/Hub/Hub.Remove.t.sol @@ -150,7 +150,7 @@ contract HubRemoveTest is HubBase { // only remaining added amount are fees assertEq( assetData.liquidity, - hub1.getAsset(assetId).realizedFees + _calculateBurntInterest(hub1, assetId), + hub1.getAsset(assetId).realizedFeesRay + _calculateBurntInterest(hub1, assetId), 'asset liquidity after' ); assertEq( @@ -177,7 +177,8 @@ contract HubRemoveTest is HubBase { function test_remove_all_with_interest() public { uint256 addAmount = 100e18; - uint256 initialLiquidity = hub1.getAsset(daiAssetId).liquidity; + uint256 initialLiquidity = hub1.getAsset(daiAssetId).liquidity + + hub1.getAsset(daiAssetId).realizedFeesRay; // add and draw dai liquidity to accrue interest // add from spoke2, draw from spoke1 @@ -321,7 +322,7 @@ contract HubRemoveTest is HubBase { assertEq(asset.addedShares, 0, 'hub addedShares'); assertApproxEqAbs( asset.liquidity, - _calculateBurntInterest(hub1, daiAssetId) + hub1.getAsset(daiAssetId).realizedFees, + _calculateBurntInterest(hub1, daiAssetId) + hub1.getAsset(daiAssetId).realizedFeesRay, 1, 'dai liquidity' ); diff --git a/tests/unit/Hub/Hub.SpokeConfig.t.sol b/tests/unit/Hub/Hub.SpokeConfig.t.sol index c79d7cc1f..eabc4b495 100644 --- a/tests/unit/Hub/Hub.SpokeConfig.t.sol +++ b/tests/unit/Hub/Hub.SpokeConfig.t.sol @@ -20,8 +20,8 @@ contract HubSpokeConfigTest is HubBase { _updateSpokeHalted(hub1, usdxAssetId, feeReceiver, true); _updateSpokeActive(hub1, usdxAssetId, feeReceiver, true); - vm.prank(HUB_ADMIN); - hub1.mintFeeShares(usdxAssetId); + // vm.prank(HUB_ADMIN); + // hub1.mintFeeShares(usdxAssetId); // set spoke to inactive / halted; reverts _accrueLiquidityFees(hub1, spoke1, usdxAssetId); @@ -29,16 +29,16 @@ contract HubSpokeConfigTest is HubBase { _updateSpokeActive(hub1, usdxAssetId, feeReceiver, false); vm.expectRevert(IHub.SpokeNotActive.selector); - vm.prank(HUB_ADMIN); - hub1.mintFeeShares(usdxAssetId); + // vm.prank(HUB_ADMIN); + // hub1.mintFeeShares(usdxAssetId); // set spoke to active / not halted; succeeds _accrueLiquidityFees(hub1, spoke1, usdxAssetId); _updateSpokeHalted(hub1, usdxAssetId, feeReceiver, false); _updateSpokeActive(hub1, usdxAssetId, feeReceiver, true); - vm.prank(HUB_ADMIN); - hub1.mintFeeShares(usdxAssetId); + // vm.prank(HUB_ADMIN); + // hub1.mintFeeShares(usdxAssetId); // set spoke to inactive / not halted; reverts _accrueLiquidityFees(hub1, spoke1, usdxAssetId); @@ -46,8 +46,8 @@ contract HubSpokeConfigTest is HubBase { _updateSpokeActive(hub1, usdxAssetId, feeReceiver, false); vm.expectRevert(IHub.SpokeNotActive.selector); - vm.prank(HUB_ADMIN); - hub1.mintFeeShares(usdxAssetId); + // vm.prank(HUB_ADMIN); + // hub1.mintFeeShares(usdxAssetId); } function test_add_active_halted_scenarios() public { @@ -372,7 +372,7 @@ contract HubSpokeConfigTest is HubBase { skip(365 days); Utils.add(hub, assetId, address(spoke), 1e18, alice); - assertGt(hub.getAsset(assetId).realizedFees, 0); + assertGt(hub.getAsset(assetId).realizedFeesRay, 0); } function _createReportedDeficit(IHub hub, address spoke, uint256 assetId) internal { diff --git a/tests/unit/HubConfigurator.t.sol b/tests/unit/HubConfigurator.t.sol index 05804ee81..09705f3fc 100644 --- a/tests/unit/HubConfigurator.t.sol +++ b/tests/unit/HubConfigurator.t.sol @@ -398,7 +398,7 @@ contract HubConfiguratorTest is HubBase { // Accrue more fees, this time to new fee receiver skip(365 days); - Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // Utils.mintFeeShares(hub1, daiAssetId, ADMIN); assertGt( newTreasurySpoke.getSuppliedAmount(daiAssetId), @@ -429,7 +429,7 @@ contract HubConfiguratorTest is HubBase { 100e18, 365 days ); - Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // Utils.mintFeeShares(hub1, daiAssetId, ADMIN); assertGe(treasurySpoke.getSuppliedShares(daiAssetId), 0); uint256 feeShares = treasurySpoke.getSuppliedShares(daiAssetId); @@ -466,7 +466,7 @@ contract HubConfiguratorTest is HubBase { // Accrue more fees, this time to new fee receiver skip(365 days); - Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // Utils.mintFeeShares(hub1, daiAssetId, ADMIN); // Check that new fee receiver is getting the fees, and not old treasury spoke assertGt( diff --git a/tests/unit/Spoke/Spoke.AccrueLiquidityFee.EdgeCases.t.sol b/tests/unit/Spoke/Spoke.AccrueLiquidityFee.EdgeCases.t.sol index cfded4d60..2b37e29ca 100644 --- a/tests/unit/Spoke/Spoke.AccrueLiquidityFee.EdgeCases.t.sol +++ b/tests/unit/Spoke/Spoke.AccrueLiquidityFee.EdgeCases.t.sol @@ -40,7 +40,7 @@ contract SpokeAccrueLiquidityFeeEdgeCasesTest is SpokeBase { Utils.borrow(spoke1, reserveId, alice, borrowAmount, alice); skip(skipTime); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); (, uint256 premiumDebt) = spoke1.getUserDebt(reserveId, alice); assertGt(premiumDebt, 0); @@ -93,7 +93,7 @@ contract SpokeAccrueLiquidityFeeEdgeCasesTest is SpokeBase { Utils.borrow(spoke1, reserveId, bob, borrowAmount2, bob); skip(skipTime); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); assertApproxEqAbs( spoke1.getUserSuppliedAssets(reserveId, alice), diff --git a/tests/unit/Spoke/Spoke.AccrueLiquidityFee.t.sol b/tests/unit/Spoke/Spoke.AccrueLiquidityFee.t.sol index 79c2a1f8d..78541e6df 100644 --- a/tests/unit/Spoke/Spoke.AccrueLiquidityFee.t.sol +++ b/tests/unit/Spoke/Spoke.AccrueLiquidityFee.t.sol @@ -117,7 +117,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { }) ); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); assertApproxEqAbs( hub1.getSpokeAddedShares(assetId, address(treasurySpoke)), expectedFeeShares, @@ -155,7 +155,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { }) ); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); assertApproxEqAbs( hub1.getSpokeAddedShares(assetId, address(treasurySpoke)), expectedFeeShares, @@ -178,7 +178,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { // treasury expectedFeeShares = 0; - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); assertApproxEqAbs( hub1.getSpokeAddedShares(assetId, address(treasurySpoke)), expectedFeeShares, @@ -212,7 +212,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { Utils.borrow(spoke1, reserveId, alice, borrowAmount, alice); skip(365 days); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); _assertSpokeDebt( spoke1, @@ -246,7 +246,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { expectedTreasuryFees = 37.5e18; // 5% of 750 (liquidity fee on drawn debt) skip(365 days); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); _assertSpokeDebt( spoke1, @@ -282,7 +282,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { expectedTreasuryFees = 0; skip(365 days); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); _assertSpokeDebt( spoke1, @@ -327,7 +327,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { assertEq(_getUserRpStored(spoke1, alice), expectedRp); skip(365 days); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); _assertSpokeDebt( spoke1, @@ -362,7 +362,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { expectedTreasuryFees = expectedDrawnDebtAccrual.percentMulUp(liquidityFee); skip(365 days); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); _assertSpokeDebt( spoke1, @@ -450,7 +450,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { assertEq(_getUserRpStored(spoke1, alice), expectedRp); skip(365 days); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); _assertSpokeDebt( spoke1, @@ -470,7 +470,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { spoke1.setUsingAsCollateral(reserveId, false, alice); assertEq(_getUserRpStored(spoke1, alice), 50_00); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); // no change in treasury fees _assertSpokeDebt( @@ -514,7 +514,7 @@ contract SpokeAccrueLiquidityFeeTest is SpokeBase { Utils.borrow(spoke1, reserveId, alice, borrowAmount, alice); skip(365 days); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); _assertSpokeDebt( spoke1, diff --git a/tests/unit/Spoke/Spoke.Withdraw.Scenario.t.sol b/tests/unit/Spoke/Spoke.Withdraw.Scenario.t.sol index 13ffc3917..c28ef7547 100644 --- a/tests/unit/Spoke/Spoke.Withdraw.Scenario.t.sol +++ b/tests/unit/Spoke/Spoke.Withdraw.Scenario.t.sol @@ -191,7 +191,7 @@ contract SpokeWithdrawScenarioTest is SpokeBase { vm.prank(carol); spoke1.repay(params.reserveId, state.repayAmount, carol); - assertEq(hub1.getAsset(params.reserveId).realizedFees, expectedFeeAmount, 'realized fees'); + assertEq(hub1.getAsset(params.reserveId).realizedFeesRay, expectedFeeAmount, 'realized fees'); TestData[3] memory reserveData; TestUserData[3] memory aliceData; @@ -288,7 +288,7 @@ contract SpokeWithdrawScenarioTest is SpokeBase { assertEq(tokenData[state.stage].spokeBalance, 0, 'tokenData spoke balance'); assertEq( tokenData[state.stage].hubBalance, - _calculateBurntInterest(hub1, state.assetId) + hub1.getAsset(state.assetId).realizedFees, + _calculateBurntInterest(hub1, state.assetId) + hub1.getAsset(state.assetId).realizedFeesRay, 'tokenData hub balance' ); assertEq( diff --git a/tests/unit/Spoke/Spoke.Withdraw.t.sol b/tests/unit/Spoke/Spoke.Withdraw.t.sol index be2180539..9197c6e58 100644 --- a/tests/unit/Spoke/Spoke.Withdraw.t.sol +++ b/tests/unit/Spoke/Spoke.Withdraw.t.sol @@ -349,7 +349,7 @@ contract SpokeWithdrawTest is SpokeBase { onBehalfOf: bob }); - assertEq(hub1.getAsset(daiAssetId).realizedFees, expectedFeeAmount, 'realized fees'); + assertEq(hub1.getAsset(daiAssetId).realizedFeesRay, expectedFeeAmount, 'realized fees'); uint256 addExRate = getAddExRate(daiAssetId); @@ -510,7 +510,7 @@ contract SpokeWithdrawTest is SpokeBase { onBehalfOf: bob }); - assertEq(hub1.getAsset(daiAssetId).realizedFees, state.expectedFeeAmount, 'realized fees'); + assertEq(hub1.getAsset(daiAssetId).realizedFeesRay, state.expectedFeeAmount, 'realized fees'); stage = 2; reserveData[stage] = loadReserveInfo(spoke1, state.reserveId); @@ -544,7 +544,7 @@ contract SpokeWithdrawTest is SpokeBase { assertEq(tokenData[stage].spokeBalance, 0, 'tokenData spoke balance'); assertEq( tokenData[stage].hubBalance, - _calculateBurntInterest(hub1, daiAssetId) + hub1.getAsset(daiAssetId).realizedFees, + _calculateBurntInterest(hub1, daiAssetId) + hub1.getAsset(daiAssetId).realizedFeesRay, 'tokenData hub balance' ); assertEq( @@ -632,7 +632,7 @@ contract SpokeWithdrawTest is SpokeBase { // alice repays all with interest Utils.repay(spoke1, state.reserveId, alice, repayAmount, alice); - assertEq(hub1.getAsset(wbtcAssetId).realizedFees, state.expectedFeeAmount, 'realized fees'); + assertEq(hub1.getAsset(wbtcAssetId).realizedFeesRay, state.expectedFeeAmount, 'realized fees'); // number of test stages TestData[3] memory reserveData; @@ -712,7 +712,7 @@ contract SpokeWithdrawTest is SpokeBase { assertEq(tokenData[stage].spokeBalance, 0, 'tokenData spoke balance'); assertEq( tokenData[stage].hubBalance, - _calculateBurntInterest(hub1, assetId) + hub1.getAsset(assetId).realizedFees, + _calculateBurntInterest(hub1, assetId) + hub1.getAsset(assetId).realizedFeesRay, 'tokenData hub balance' ); assertEq(underlying.balanceOf(alice), 0, 'alice balance'); @@ -757,7 +757,7 @@ contract SpokeWithdrawTest is SpokeBase { uint256 repayAmount = spoke1.getUserTotalDebt(state.reserveId, alice); Utils.repay(spoke1, state.reserveId, alice, repayAmount, alice); - assertEq(hub1.getAsset(daiAssetId).realizedFees, state.expectedFeeAmount, 'realized fees'); + assertEq(hub1.getAsset(daiAssetId).realizedFeesRay, state.expectedFeeAmount, 'realized fees'); uint256 stage = 0; reserveData[stage] = loadReserveInfo(spoke1, state.reserveId); @@ -825,7 +825,7 @@ contract SpokeWithdrawTest is SpokeBase { assertEq(tokenData[stage].spokeBalance, 0, 'tokenData spoke balance'); assertEq( tokenData[stage].hubBalance, - _calculateBurntInterest(hub1, daiAssetId) + hub1.getAsset(daiAssetId).realizedFees, + _calculateBurntInterest(hub1, daiAssetId) + hub1.getAsset(daiAssetId).realizedFeesRay, 'tokenData hub balance' ); assertEq( @@ -905,7 +905,7 @@ contract SpokeWithdrawTest is SpokeBase { Utils.repay(spoke1, state.reserveId, alice, repayAmount, alice); - assertEq(hub1.getAsset(assetId).realizedFees, state.expectedFeeAmount, 'realized fees'); + assertEq(hub1.getAsset(assetId).realizedFeesRay, state.expectedFeeAmount, 'realized fees'); // number of test stages TestData[3] memory reserveData; @@ -987,7 +987,7 @@ contract SpokeWithdrawTest is SpokeBase { assertEq(tokenData[stage].spokeBalance, 0, 'tokenData spoke balance'); assertEq( tokenData[stage].hubBalance, - _calculateBurntInterest(hub1, assetId) + hub1.getAsset(assetId).realizedFees, + _calculateBurntInterest(hub1, assetId) + hub1.getAsset(assetId).realizedFeesRay, 'tokenData hub balance' ); assertEq(underlying.balanceOf(alice), 0, 'alice balance'); diff --git a/tests/unit/Spoke/TreasurySpoke.t.sol b/tests/unit/Spoke/TreasurySpoke.t.sol index fe085d72a..3249c0428 100644 --- a/tests/unit/Spoke/TreasurySpoke.t.sol +++ b/tests/unit/Spoke/TreasurySpoke.t.sol @@ -93,12 +93,12 @@ contract TreasurySpokeTest is SpokeBase { _openDebtPosition(spoke1, getReserveIdByAssetId(spoke1, hub1, daiAssetId), 100e18, true); skip(365 days); - assertEq(hub1.getAsset(daiAssetId).realizedFees, 0, 'fees'); // fees not yet accrued + assertEq(hub1.getAsset(daiAssetId).realizedFeesRay, 0, 'fees'); // fees not yet accrued uint256 expectedFeeAmount = _calcUnrealizedFees(hub1, daiAssetId); - Utils.mintFeeShares(hub1, daiAssetId, ADMIN); + // Utils.mintFeeShares(hub1, daiAssetId, ADMIN); - assertEq(hub1.getAsset(daiAssetId).realizedFees, 0, 'realized fees after minting'); + assertEq(hub1.getAsset(daiAssetId).realizedFeesRay, 0, 'realized fees after minting'); assertGe( treasurySpoke.getSuppliedShares(daiAssetId), hub1.previewAddByAssets(daiAssetId, expectedFeeAmount) @@ -202,15 +202,15 @@ contract TreasurySpokeTest is SpokeBase { address tempUser = _openDebtPosition(spoke1, reserveId, amount, true); skip(skipTime); - assertEq(hub1.getAsset(assetId).realizedFees, 0, 'fees'); // fees not yet accrued + assertEq(hub1.getAsset(assetId).realizedFeesRay, 0, 'fees'); // fees not yet accrued uint256 expectedFeeAmount = _calcUnrealizedFees(hub1, assetId); - Utils.mintFeeShares(hub1, assetId, ADMIN); + // Utils.mintFeeShares(hub1, assetId, ADMIN); uint256 fees = treasurySpoke.getSuppliedAmount(assetId); assertEq(fees, expectedFeeAmount, 'supplied amount of fees'); - assertEq(hub1.getAsset(assetId).realizedFees, 0, 'realized fees after minting'); + assertEq(hub1.getAsset(assetId).realizedFeesRay, 0, 'realized fees after minting'); assertApproxEqAbs( hub1.getSpokeAddedAssets(assetId, address(treasurySpoke)), hub1.getAssetTotalOwed(assetId) - amount,