Skip to content

Commit

Permalink
Merge pull request aave-dao#71 from bgd-labs/fix/mixbytes
Browse files Browse the repository at this point in the history
fix: mixbytes stata fixes
  • Loading branch information
sakulstra authored Nov 13, 2024
2 parents 077c99e + c2f6db7 commit 45ae3c0
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 92 deletions.
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

0 comments on commit 45ae3c0

Please sign in to comment.