@@ -105,7 +105,7 @@ contract AStETH is VersionedInitializable, IncentivizedERC20, IAToken {
105105 uint256 amount ,
106106 uint256 index
107107 ) external override onlyLendingPool {
108- uint256 amountScaled = amount. rayDiv ( _stEthRebasingIndex ()). rayDiv ( index);
108+ uint256 amountScaled = _toInternalAmount (amount, _stEthRebasingIndex (), index);
109109 require (amountScaled != 0 , Errors.CT_INVALID_BURN_AMOUNT);
110110 _burn (user, amountScaled);
111111
@@ -130,7 +130,7 @@ contract AStETH is VersionedInitializable, IncentivizedERC20, IAToken {
130130 ) external override onlyLendingPool returns (bool ) {
131131 uint256 previousBalance = super .balanceOf (user);
132132
133- uint256 amountScaled = amount. rayDiv ( _stEthRebasingIndex ()). rayDiv ( index);
133+ uint256 amountScaled = _toInternalAmount (amount, _stEthRebasingIndex (), index);
134134 require (amountScaled != 0 , Errors.CT_INVALID_MINT_AMOUNT);
135135 _mint (user, amountScaled);
136136
@@ -152,10 +152,10 @@ contract AStETH is VersionedInitializable, IncentivizedERC20, IAToken {
152152 }
153153
154154 // Compared to the normal mint, we don't check for rounding errors.
155- // The amount to mint can easily be very small since it is a fraction of the interest ccrued .
155+ // The amount to mint can easily be very small since it is a fraction of the interest accrued .
156156 // In that case, the treasury will experience a (very small) loss, but it
157- // wont cause potentially valid transactions to fail.
158- _mint (RESERVE_TREASURY_ADDRESS, amount. rayDiv ( _stEthRebasingIndex ()). rayDiv ( index));
157+ // won't cause potentially valid transactions to fail.
158+ _mint (RESERVE_TREASURY_ADDRESS, _toInternalAmount (amount, _stEthRebasingIndex (), index));
159159
160160 emit Transfer (address (0 ), RESERVE_TREASURY_ADDRESS, amount);
161161 emit Mint (RESERVE_TREASURY_ADDRESS, amount, index);
@@ -207,6 +207,17 @@ contract AStETH is VersionedInitializable, IncentivizedERC20, IAToken {
207207 return _scaledBalanceOf (user, _stEthRebasingIndex ());
208208 }
209209
210+ /**
211+ * @dev Returns the internal balance of the user. The internal balance is the balance of
212+ * the underlying asset of the user (sum of deposits of the user), divided by the current
213+ * liquidity index at the moment of the update and by the current stETH rebasing index.
214+ * @param user The user whose balance is calculated
215+ * @return The internal balance of the user
216+ **/
217+ function internalBalanceOf (address user ) external view returns (uint256 ) {
218+ return super .balanceOf (user);
219+ }
220+
210221 /**
211222 * @dev Returns the scaled balance of the user and the scaled total supply.
212223 * @param user The address of the user
@@ -247,6 +258,15 @@ contract AStETH is VersionedInitializable, IncentivizedERC20, IAToken {
247258 return _scaledTotalSupply (_stEthRebasingIndex ());
248259 }
249260
261+ /**
262+ * @dev Returns the internal total supply of the token. Represents
263+ * sum(debt/_stEthRebasingIndex/liquidityIndex).
264+ * @return the internal total supply
265+ */
266+ function internalTotalSupply () external view returns (uint256 ) {
267+ return super .totalSupply ();
268+ }
269+
250270 /**
251271 * @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer
252272 * assets in borrow(), withdraw() and flashLoan()
@@ -315,15 +335,17 @@ contract AStETH is VersionedInitializable, IncentivizedERC20, IAToken {
315335 uint256 amount ,
316336 bool validate
317337 ) internal {
318- uint256 index = POOL.getReserveNormalizedIncome (UNDERLYING_ASSET_ADDRESS);
338+ uint256 aaveLiquidityIndex = POOL.getReserveNormalizedIncome (UNDERLYING_ASSET_ADDRESS);
339+ uint256 stEthRebasingIndex = _stEthRebasingIndex ();
319340
320- uint256 rebasingIndex = _stEthRebasingIndex ();
321- uint256 fromBalanceBefore = _scaledBalanceOf (from, rebasingIndex ).rayMul (index );
322- uint256 toBalanceBefore = _scaledBalanceOf (to, rebasingIndex ).rayMul (index );
341+ uint256 fromBalanceBefore =
342+ _scaledBalanceOf (from, stEthRebasingIndex ).rayMul (aaveLiquidityIndex );
343+ uint256 toBalanceBefore = _scaledBalanceOf (to, stEthRebasingIndex ).rayMul (aaveLiquidityIndex );
323344
324- super ._transfer (from, to, amount. rayDiv (rebasingIndex). rayDiv (index ));
345+ super ._transfer (from, to, _toInternalAmount (amount, stEthRebasingIndex, aaveLiquidityIndex ));
325346
326347 if (validate) {
348+ require (fromBalanceBefore >= amount, 'ERC20: transfer amount exceeds balance ' );
327349 POOL.finalizeTransfer (
328350 UNDERLYING_ASSET_ADDRESS,
329351 from,
@@ -334,7 +356,7 @@ contract AStETH is VersionedInitializable, IncentivizedERC20, IAToken {
334356 );
335357 }
336358
337- emit BalanceTransfer (from, to, amount, index );
359+ emit BalanceTransfer (from, to, amount, aaveLiquidityIndex );
338360 }
339361
340362 /**
@@ -351,42 +373,33 @@ contract AStETH is VersionedInitializable, IncentivizedERC20, IAToken {
351373 _transfer (from, to, amount, true );
352374 }
353375
354- /**
355- * @return Current rebasin index of stETH in RAY
356- **/
357- function _stEthRebasingIndex () internal view returns (uint256 ) {
358- // Below expression returns how much Ether corresponds
359- // to 10 ** 27 shares. 10 ** 27 was taken to provide
360- // same precision as AAVE's liquidity index, which
361- // counted in RAY's (decimals with 27 digits).
362- return ILido (UNDERLYING_ASSET_ADDRESS).getPooledEthByShares (1e27 );
363- }
364-
365376 function _scaledBalanceOf (address user , uint256 rebasingIndex ) internal view returns (uint256 ) {
366- return super .balanceOf (user).rayMul (rebasingIndex);
377+ return super .balanceOf (user).mul (rebasingIndex). div (WadRayMath.RAY );
367378 }
368379
369380 function _scaledTotalSupply (uint256 rebasingIndex ) internal view returns (uint256 ) {
370- return super .totalSupply ().rayMul (rebasingIndex);
381+ return super .totalSupply ().mul (rebasingIndex). div (WadRayMath.RAY );
371382 }
372383
373384 /**
374- * @dev Returns the internal balance of the user. The internal balance is the balance of
375- * the underlying asset of the user (sum of deposits of the user), divided by the current
376- * liquidity index at the moment of the update and by the current stETH rebasing index.
377- * @param user The user whose balance is calculated
378- * @return The internal balance of the user
385+ * @return Current rebasing index of stETH in RAY
379386 **/
380- function internalBalanceOf (address user ) external view returns (uint256 ) {
381- return super .balanceOf (user);
387+ function _stEthRebasingIndex () internal view returns (uint256 ) {
388+ // Returns amount of stETH corresponding to 10**27 stETH shares.
389+ // The 10**27 is picked to provide the same precision as the AAVE
390+ // liquidity index, which is in RAY (10**27).
391+ return ILido (UNDERLYING_ASSET_ADDRESS).getPooledEthByShares (WadRayMath.RAY);
382392 }
383393
384394 /**
385- * @dev Returns the internal total supply of the token. Represents
386- * sum(debt/_stEthRebasingIndex/liquidityIndex).
387- * @return the internal total supply
395+ * @dev Converts amount of astETH to internal shares, based
396+ * on stEthRebasingIndex and aaveLiquidityIndex.
388397 */
389- function internalTotalSupply () external view returns (uint256 ) {
390- return super .totalSupply ();
398+ function _toInternalAmount (
399+ uint256 amount ,
400+ uint256 stEthRebasingIndex ,
401+ uint256 aaveLiquidityIndex
402+ ) internal view returns (uint256 ) {
403+ return amount.mul (WadRayMath.RAY).div (stEthRebasingIndex).rayDiv (aaveLiquidityIndex);
391404 }
392405}
0 commit comments