Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT
2 : : pragma solidity ^0.8.10;
3 : :
4 : : import {SafeCast} from '../../../dependencies/openzeppelin/contracts/SafeCast.sol';
5 : : import {Errors} from '../../libraries/helpers/Errors.sol';
6 : : import {WadRayMath} from '../../libraries/math/WadRayMath.sol';
7 : : import {IPool} from '../../../interfaces/IPool.sol';
8 : : import {IScaledBalanceToken} from '../../../interfaces/IScaledBalanceToken.sol';
9 : : import {MintableIncentivizedERC20} from './MintableIncentivizedERC20.sol';
10 : :
11 : : /**
12 : : * @title ScaledBalanceTokenBase
13 : : * @author Aave
14 : : * @notice Basic ERC20 implementation of scaled balance token
15 : : */
16 : : abstract contract ScaledBalanceTokenBase is MintableIncentivizedERC20, IScaledBalanceToken {
17 : : using WadRayMath for uint256;
18 : : using SafeCast for uint256;
19 : :
20 : : /**
21 : : * @dev Constructor.
22 : : * @param pool The reference to the main Pool contract
23 : : * @param name The name of the token
24 : : * @param symbol The symbol of the token
25 : : * @param decimals The number of decimals of the token
26 : : */
27 : : constructor(
28 : : IPool pool,
29 : : string memory name,
30 : : string memory symbol,
31 : : uint8 decimals
32 : : ) MintableIncentivizedERC20(pool, name, symbol, decimals) {
33 : : // Intentionally left blank
34 : : }
35 : :
36 : : /// @inheritdoc IScaledBalanceToken
37 : : function scaledBalanceOf(address user) external view override returns (uint256) {
38 : 88301 : return super.balanceOf(user);
39 : : }
40 : :
41 : : /// @inheritdoc IScaledBalanceToken
42 : : function getScaledUserBalanceAndSupply(
43 : : address user
44 : : ) external view override returns (uint256, uint256) {
45 : 21 : return (super.balanceOf(user), super.totalSupply());
46 : : }
47 : :
48 : : /// @inheritdoc IScaledBalanceToken
49 : : function scaledTotalSupply() public view virtual override returns (uint256) {
50 : 133450 : return super.totalSupply();
51 : : }
52 : :
53 : : /// @inheritdoc IScaledBalanceToken
54 : : function getPreviousIndex(address user) external view virtual override returns (uint256) {
55 : 39 : return _userState[user].additionalData;
56 : : }
57 : :
58 : : /**
59 : : * @notice Implements the basic logic to mint a scaled balance token.
60 : : * @param caller The address performing the mint
61 : : * @param onBehalfOf The address of the user that will receive the scaled tokens
62 : : * @param amount The amount of tokens getting minted
63 : : * @param index The next liquidity index of the reserve
64 : : * @return `true` if the the previous balance of the user was 0
65 : : */
66 : : function _mintScaled(
67 : : address caller,
68 : : address onBehalfOf,
69 : : uint256 amount,
70 : : uint256 index
71 : : ) internal returns (bool) {
72 : 62622 : uint256 amountScaled = amount.rayDiv(index);
73 : 62622 : require(amountScaled != 0, Errors.INVALID_MINT_AMOUNT);
74 : :
75 : 62621 : uint256 scaledBalance = super.balanceOf(onBehalfOf);
76 : 62621 : uint256 balanceIncrease = scaledBalance.rayMul(index) -
77 : 62621 : scaledBalance.rayMul(_userState[onBehalfOf].additionalData);
78 : :
79 : 62621 : _userState[onBehalfOf].additionalData = index.toUint128();
80 : :
81 : 62621 : _mint(onBehalfOf, amountScaled.toUint128());
82 : :
83 : 62621 : uint256 amountToMint = amount + balanceIncrease;
84 : 62621 : emit Transfer(address(0), onBehalfOf, amountToMint);
85 : 62621 : emit Mint(caller, onBehalfOf, amountToMint, balanceIncrease, index);
86 : :
87 : 62621 : return (scaledBalance == 0);
88 : : }
89 : :
90 : : /**
91 : : * @notice Implements the basic logic to burn a scaled balance token.
92 : : * @dev In some instances, a burn transaction will emit a mint event
93 : : * if the amount to burn is less than the interest that the user accrued
94 : : * @param user The user which debt is burnt
95 : : * @param target The address that will receive the underlying, if any
96 : : * @param amount The amount getting burned
97 : : * @param index The variable debt index of the reserve
98 : : */
99 : : function _burnScaled(address user, address target, uint256 amount, uint256 index) internal {
100 : 26088 : uint256 amountScaled = amount.rayDiv(index);
101 : 26088 : require(amountScaled != 0, Errors.INVALID_BURN_AMOUNT);
102 : :
103 : 26087 : uint256 scaledBalance = super.balanceOf(user);
104 : 26087 : uint256 balanceIncrease = scaledBalance.rayMul(index) -
105 : 26087 : scaledBalance.rayMul(_userState[user].additionalData);
106 : :
107 : 26087 : _userState[user].additionalData = index.toUint128();
108 : :
109 : 26087 : _burn(user, amountScaled.toUint128());
110 : :
111 : 26086 : if (balanceIncrease > amount) {
112 : 1560 : uint256 amountToMint = balanceIncrease - amount;
113 : 1560 : emit Transfer(address(0), user, amountToMint);
114 : 1560 : emit Mint(user, user, amountToMint, balanceIncrease, index);
115 : : } else {
116 : 24526 : uint256 amountToBurn = amount - balanceIncrease;
117 : 24526 : emit Transfer(user, address(0), amountToBurn);
118 : 24526 : emit Burn(user, target, amountToBurn, balanceIncrease, index);
119 : : }
120 : : }
121 : :
122 : : /**
123 : : * @notice Implements the basic logic to transfer scaled balance tokens between two users
124 : : * @dev It emits a mint event with the interest accrued per user
125 : : * @param sender The source address
126 : : * @param recipient The destination address
127 : : * @param amount The amount getting transferred
128 : : * @param index The next liquidity index of the reserve
129 : : */
130 : : function _transfer(address sender, address recipient, uint256 amount, uint256 index) internal {
131 : 25056 : uint256 senderScaledBalance = super.balanceOf(sender);
132 : 25056 : uint256 senderBalanceIncrease = senderScaledBalance.rayMul(index) -
133 : 25056 : senderScaledBalance.rayMul(_userState[sender].additionalData);
134 : :
135 : 25056 : uint256 recipientScaledBalance = super.balanceOf(recipient);
136 : 25056 : uint256 recipientBalanceIncrease = recipientScaledBalance.rayMul(index) -
137 : 25056 : recipientScaledBalance.rayMul(_userState[recipient].additionalData);
138 : :
139 : 25056 : _userState[sender].additionalData = index.toUint128();
140 : 25056 : _userState[recipient].additionalData = index.toUint128();
141 : :
142 : 25056 : super._transfer(sender, recipient, amount.rayDiv(index).toUint128());
143 : :
144 : 25056 : if (senderBalanceIncrease > 0) {
145 : 1003 : emit Transfer(address(0), sender, senderBalanceIncrease);
146 : 1003 : emit Mint(_msgSender(), sender, senderBalanceIncrease, senderBalanceIncrease, index);
147 : : }
148 : :
149 : 25056 : if (sender != recipient && recipientBalanceIncrease > 0) {
150 : 1 : emit Transfer(address(0), recipient, recipientBalanceIncrease);
151 : 1 : emit Mint(_msgSender(), recipient, recipientBalanceIncrease, recipientBalanceIncrease, index);
152 : : }
153 : :
154 : 25056 : emit Transfer(sender, recipient, amount);
155 : : }
156 : : }
|