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

fix: mixbytes statav2 review #36

Closed
wants to merge 6 commits into from
Closed
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
9 changes: 4 additions & 5 deletions certora/basic/harness/DummyContract.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

contract DummyContract {
function havoc_all_dummy() external {
// havoc_all_dummy_internal();
}
function havoc_all_dummy() external {
// havoc_all_dummy_internal();
}

//function havoc_all_dummy_internal() internal {}
//function havoc_all_dummy_internal() internal {}
}
24 changes: 16 additions & 8 deletions certora/basic/harness/EModeConfigurationHarness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,29 @@ contract EModeConfigurationHarness {

function setCollateral(uint256 reserveIndex, bool enabled) public {
DataTypes.EModeCategory memory emode_new = eModeCategory;
eModeCategory.collateralBitmap = EModeConfiguration.setReserveBitmapBit(emode_new.collateralBitmap, reserveIndex, enabled);
eModeCategory.collateralBitmap = EModeConfiguration.setReserveBitmapBit(
emode_new.collateralBitmap,
reserveIndex,
enabled
);
}

function isCollateralAsset(uint256 reserveIndex) public returns (bool) {
return EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.collateralBitmap, reserveIndex);
return
EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.collateralBitmap, reserveIndex);
}



function setBorrowable(uint256 reserveIndex,bool enabled) public {
function setBorrowable(uint256 reserveIndex, bool enabled) public {
DataTypes.EModeCategory memory emode_new = eModeCategory;
eModeCategory.borrowableBitmap = EModeConfiguration.setReserveBitmapBit(emode_new.borrowableBitmap, reserveIndex, enabled);
eModeCategory.borrowableBitmap = EModeConfiguration.setReserveBitmapBit(
emode_new.borrowableBitmap,
reserveIndex,
enabled
);
}

function isBorrowableAsset(uint256 reserveIndex) public returns (bool) {
return EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.borrowableBitmap, reserveIndex);
return
EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.borrowableBitmap, reserveIndex);
}
}
20 changes: 10 additions & 10 deletions certora/basic/harness/PoolInstanceHarness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ import {DataTypes} from '../munged/contracts/protocol/libraries/types/DataTypes.
import {ReserveLogic} from '../munged/contracts/protocol/libraries/logic/ReserveLogic.sol';
import {WadRayMath} from '../munged/contracts/protocol/libraries/math/WadRayMath.sol';

import {DummyContract} from "./DummyContract.sol";

import {DummyContract} from './DummyContract.sol';

contract PoolInstanceHarness is PoolInstance {
DummyContract DUMMY;

constructor(IPoolAddressesProvider provider) PoolInstance(provider) {}

function cumulateToLiquidityIndex(address asset,
uint256 totalLiquidity,
uint256 amount
) external returns (uint256) {
function cumulateToLiquidityIndex(
address asset,
uint256 totalLiquidity,
uint256 amount
) external returns (uint256) {
return ReserveLogic.cumulateToLiquidityIndex(_reserves[asset], totalLiquidity, amount);
}

Expand All @@ -34,12 +34,12 @@ contract PoolInstanceHarness is PoolInstance {
function havoc_all() public {
DUMMY.havoc_all_dummy();
}

function rayMul(uint256 a, uint256 b) external returns (uint256) {
return WadRayMath.rayMul(a,b);
return WadRayMath.rayMul(a, b);
}

function rayDiv(uint256 a, uint256 b) external returns (uint256) {
return WadRayMath.rayDiv(a,b);
return WadRayMath.rayDiv(a, b);
}
}
2 changes: 1 addition & 1 deletion certora/stata/harness/pool/SymbolicLendingPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ contract SymbolicLendingPool {
res.isolationModeTotalDebt = reserveLegacy.isolationModeTotalDebt;
return res;
}

function getReserveDataExtended(
address asset
) external view returns (DataTypes.ReserveData memory) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ abstract contract ERC20AaveLMUpgradeable is ERC20Upgradeable, IERC20AaveLM {
struct ERC20AaveLMStorage {
address _referenceAsset; // a/v token to track rewards on INCENTIVES_CONTROLLER
address[] _rewardTokens;
mapping(address user => RewardIndexCache cache) _startIndex;
mapping(address reward => RewardIndexCache cache) _startIndex;
mapping(address user => mapping(address reward => UserRewardsData cache)) _userRewardsData;
}

Expand All @@ -39,6 +39,9 @@ abstract contract ERC20AaveLMUpgradeable is ERC20Upgradeable, IERC20AaveLM {
IRewardsController public immutable INCENTIVES_CONTROLLER;

constructor(IRewardsController rewardsController) {
if (address(rewardsController) == address(0)) {
revert ZeroIncentivesControllerIsForbidden();
}
INCENTIVES_CONTROLLER = rewardsController;
}

Expand Down Expand Up @@ -195,11 +198,11 @@ abstract contract ERC20AaveLMUpgradeable is ERC20Upgradeable, IERC20AaveLM {
}

/**
* @notice Compute the pending in WAD. Pending is the amount to add (not yet unclaimed) rewards in WAD.
* @notice Compute the pending in asset decimals. Pending is the amount to add (not yet unclaimed) rewards in asset decimals.
* @param balance The balance of the user
* @param rewardsIndexOnLastInteraction The index which was on the last interaction of the user
* @param currentRewardsIndex The current rewards index in the system
* @return The amount of pending rewards in WAD
* @return The amount of pending rewards in asset decimals
*/
function _getPendingRewards(
uint256 balance,
Expand All @@ -216,7 +219,7 @@ abstract contract ERC20AaveLMUpgradeable is ERC20Upgradeable, IERC20AaveLM {
* @notice Compute the claimable rewards for a user
* @param user The address of the user
* @param reward The address of the reward
* @param balance The balance of the user in WAD
* @param balance The balance of the user in asset decimals
* @param currentRewardsIndex The current rewards index
* @return The total rewards that can be claimed by the user (if `fresh` flag true, after updating rewards)
*/
Expand Down Expand Up @@ -299,7 +302,7 @@ abstract contract ERC20AaveLMUpgradeable is ERC20Upgradeable, IERC20AaveLM {

ERC20AaveLMStorage storage $ = _getERC20AaveLMStorage();
$._rewardTokens.push(reward);
$._startIndex[reward] = RewardIndexCache(true, startIndex.toUint240());
$._startIndex[reward] = RewardIndexCache(true, startIndex.toUint248());

emit RewardTokenRegistered(reward, startIndex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ abstract contract ERC4626StataTokenUpgradeable is ERC4626Upgradeable, IERC4626St

///@inheritdoc IERC4626StataToken
function depositATokens(uint256 assets, address receiver) external returns (uint256) {
// because aToken is rebasable, we allow user to specify more then he has to compensate growth during the tx mining
uint256 actualUserBalance = IERC20(aToken()).balanceOf(_msgSender());
if (assets > actualUserBalance) {
assets = actualUserBalance;
}

uint256 shares = previewDeposit(assets);
_deposit(_msgSender(), receiver, assets, shares, false);

Expand All @@ -89,14 +95,27 @@ abstract contract ERC4626StataTokenUpgradeable is ERC4626Upgradeable, IERC4626St
SignatureParams memory sig,
bool depositToAave
) external returns (uint256) {
IERC20Permit assetToDeposit = IERC20Permit(
depositToAave ? asset() : address(_getERC4626StataTokenStorage()._aToken)
);
address assetToDeposit = depositToAave ? asset() : aToken();

try
assetToDeposit.permit(_msgSender(), address(this), assets, deadline, sig.v, sig.r, sig.s)
IERC20Permit(assetToDeposit).permit(
_msgSender(),
address(this),
assets,
deadline,
sig.v,
sig.r,
sig.s
)
{} catch {}

// because aToken is rebasable, we allow user to specify more then he has to compensate growth during the tx mining
// to make it consistent, we keep the same behaviour for the normal underlying too
uint256 actualUserBalance = IERC20(assetToDeposit).balanceOf(_msgSender());
if (assets > actualUserBalance) {
assets = actualUserBalance;
}

uint256 shares = previewDeposit(assets);
_deposit(_msgSender(), receiver, assets, shares, depositToAave);
return shares;
Expand Down Expand Up @@ -180,7 +199,7 @@ abstract contract ERC4626StataTokenUpgradeable is ERC4626Upgradeable, IERC4626St
// return remaining supply cap margin
uint256 currentSupply = (IAToken(reserveData.aTokenAddress).scaledTotalSupply() +
reserveData.accruedToTreasury).mulDiv(_rate(), RAY, Math.Rounding.Ceil);
return currentSupply > supplyCap ? 0 : supplyCap - currentSupply;
return currentSupply >= supplyCap ? 0 : supplyCap - currentSupply;
}

///@inheritdoc IERC4626StataToken
Expand Down
10 changes: 5 additions & 5 deletions src/contracts/extensions/static-a-token/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ For this project, the security procedures applied/being finished are:
The `StaticATokenLM`(v1) was based on solmate.
To allow more flexibility the new `StataTokenV2`(v2) is based on [openzeppelin-contracts-upgradeable](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable) which relies on [`ERC-7201`](https://eips.ethereum.org/EIPS/eip-7201) which isolates storage per contract.

The implementation is seperated in two ERC20 extentions and one actual "merger" contract stitching functionality together.
The implementation is separated in two ERC20 extensions and one actual "merger" contract stitching functionality together.

1. `ERC20AaveLM` is an abstract contract implementing the forwarding of liquidity mining from an underlying AaveERC20 - an ERC20 implementing `scaled` functions - to holders of a wrapper contract.
The abstract contract is following `ERC-7201` and acts as erc20 extension.
Expand All @@ -70,13 +70,13 @@ To account for that specific use-case a dedicated `depositWithPermit` was added.
### Direct AToken Interaction

In v1 deposit was overleaded to allow underlying & aToken deposits.
While this appraoch was fine it seemed unclean and caused some confusion with integrators.
While this approach was fine it seemed unclean and caused some confusion with integrators.
Therefore v2 introduces dedicated `depositATokens` and `redeemATokens` methods.

#### PermissionlessRescuable
#### Rescuable

[PermissionlessRescuable](https://github.com/bgd-labs/solidity-utils/blob/main/src/contracts/utils/PermissionlessRescuable.sol) has been applied to
the `StataTokenV2` which will allow the anyone to rescue surplus tokens on the contract to the treasury.
[Rescuable](https://github.com/bgd-labs/solidity-utils/blob/main/src/contracts/utils/Rescuable.sol) has been applied to
the `StataTokenV2` which will allow the aclAdmin to rescue surplus tokens on the contract to the treasury.

#### Pausability

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ pragma solidity ^0.8.10;

interface IERC20AaveLM {
struct UserRewardsData {
uint128 rewardsIndexOnLastInteraction; // (in RAYs)
uint128 unclaimedRewards; // (in RAYs)
uint128 rewardsIndexOnLastInteraction;
uint128 unclaimedRewards;
}

struct RewardIndexCache {
bool isRegistered;
uint248 lastUpdatedIndex;
}

error ZeroIncentivesControllerIsForbidden();
error InvalidClaimer(address claimer);
error RewardNotInitialized(address reward);

Expand Down Expand Up @@ -58,18 +59,18 @@ interface IERC20AaveLM {
function getTotalClaimableRewards(address reward) external view returns (uint256);

/**
* @notice Get the total claimable rewards for a user in WAD
* @notice Get the total claimable rewards for a user in asset decimals
* @param user The address of the user
* @param reward The reward to claim
* @return uint256 The claimable amount of rewards in WAD
* @return uint256 The claimable amount of rewards in asset decimals
*/
function getClaimableRewards(address user, address reward) external view returns (uint256);

/**
* @notice The unclaimed rewards for a user in WAD
* @notice The unclaimed rewards for a user in asset decimals
* @param user The address of the user
* @param reward The reward to claim
* @return uint256 The unclaimed amount of rewards in WAD
* @return uint256 The unclaimed amount of rewards in asset decimals
*/
function getUnclaimedRewards(address user, address reward) external view returns (uint256);

Expand Down
5 changes: 5 additions & 0 deletions tests/extensions/static-a-token/ERC20AaveLMUpgradable.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ contract ERC20AaveLMUpgradableTest is TestnetProcedures {
);
}

function test_zeroIncentivesController() external {
vm.expectRevert(IERC20AaveLM.ZeroIncentivesControllerIsForbidden.selector);
new MockERC20AaveLMUpgradeable(IRewardsController(address(0)));
}

function test_noRewardsInitialized() external {
vm.expectRevert(
abi.encodeWithSelector(IERC20AaveLM.RewardNotInitialized.selector, rewardToken)
Expand Down
Loading
Loading